diff --git a/.gitignore b/.gitignore index bc4bd439..9b871d4f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /**/.idea /**/node_modules /**/.orbitmines +/**/.ether /Ether/.html/src-tauri/target -/Ether/.html/src-tauri/gen \ No newline at end of file +/Ether/.html/src-tauri/gen diff --git a/@ether/library/Index.ray b/@ether/library/Index.ray index 27de4d89..2c951f13 100644 --- a/@ether/library/Index.ray +++ b/@ether/library/Index.ray @@ -424,7 +424,6 @@ Language namespace MessagePack < Language(".msgpack") ; location &= "https://github.com/msgpack/msgpack" & "https://msgpack.org/" namespace Michelson < Language(".tz") ; location &= "https://tezos.gitlab.io/active/michelson.html" & "https://docs.tezos.com/smart-contracts/languages/michelson" namespace UnitTest < Language(".tzt") - namespace MiniZinc < Language(".mzn") ; location &= "https://github.com/MiniZinc/libminizinc" namespace Mizar < Language(".miz") ; location &= "https://mizar.uwb.edu.pl/" & "https://en.wikipedia.org/wiki/Mizar_system" namespace Abstract < Language(".abs") namespace Mojo < Language(".mojo" | ".🔥") ; location &= "https://github.com/modular/modular" & "https://en.wikipedia.org/wiki/Mojo_(programming_language)" @@ -706,7 +705,7 @@ Language namespace IntermediateLanguage < Language(".wyil") namespace Wasp < Language(".wasp") ; location &= "https://github.com/wasp-lang/wasp" & "https://wasp.sh/" namespace Whitespace < Language(".ws") ; location &= "https://esolangs.org/wiki/Whitespace" & "https://en.wikipedia.org/wiki/Whitespace_(programming_language)" - namespace Wren < Language(".wren") ; location &= "https://github.com/wren-lang/wren" & "https://wren.io/" + namespace Wren < Language(".wren") ; location &= "https://github.com/wren-lang/wren" & "https://wren.io/" & "https://en.wikipedia.org/wiki/Wren_(programming_language)" namespace wgpu < Library ; location &= "https://github.com/gfx-rs/wgpu" namespace Wireworld < Tool ; location &= "https://en.wikipedia.org/wiki/Wireworld" namespace MCell < Language(".mcl") @@ -743,6 +742,879 @@ Language namespace YAML < Language(".yaml" | ".yml") ; location &= "https://github.com/yaml" & "https://yaml.org/" & "https://en.wikipedia.org/wiki/YAML" namespace Zsh | "Z Shell" < Language(".zsh") ; location &= "https://www.zsh.org/" & "https://en.wikipedia.org/wiki/Z_shell" + // --- New entries: Programming Languages --- + namespace Ante < Language(".an") ; location &= "https://github.com/jfecher/ante" + namespace Arturo < Language(".art") ; location &= "https://github.com/arturo-lang/arturo" & "https://arturo-lang.io/" + namespace Automath < Language(".aut") ; location &= "https://www.cs.ru.nl/~freek/aut/" & "https://en.wikipedia.org/wiki/Automath" + namespace Aya < Language(".aya") ; location &= "https://github.com/aya-prover/aya-dev" & "https://www.aya-prover.org/" + namespace Borgo < Language(".brg") ; location &= "https://github.com/borgo-lang/borgo" & "https://borgo-lang.github.io/" + namespace Darklang | "Dark" < Language() ; location &= "https://github.com/darklang/dark" & "https://darklang.com/" + namespace Emojicode < Language(".emojic") ; location &= "https://github.com/emojicode/emojicode" & "https://www.emojicode.org/" + namespace Gluon < Language(".glu") ; location &= "https://github.com/gluon-lang/gluon" & "https://gluon-lang.org/" + namespace Gravity < Language(".gravity") ; location &= "https://github.com/marcobambini/gravity" & "https://marcobambini.github.io/gravity/" + namespace Hare < Language(".ha") ; location &= "https://harelang.org/" & "https://en.wikipedia.org/wiki/Hare_(programming_language)" + namespace Haxe < Language(".hx") ; location &= "https://github.com/HaxeFoundation/haxe" & "https://haxe.org/" & "https://en.wikipedia.org/wiki/Haxe" + namespace LeoAleo | "Leo (Aleo)" < Language(".leo") ; location &= "https://github.com/ProvableHQ/leo" & "https://leo-lang.org/" + namespace Lux < Language(".lux") ; location &= "https://github.com/LuxLang/lux" & "https://luxlang.github.io/lux/" + namespace Noir < Language(".nr") ; location &= "https://github.com/noir-lang/noir" & "https://noir-lang.org/" + namespace Onyx < Language(".onyx") ; location &= "https://github.com/onyxlang/onyx" & "https://www.onyxlang.io/" + namespace PostScript < Language(".ps") ; location &= "https://en.wikipedia.org/wiki/PostScript" + namespace Encapsulated < Language(".eps") + namespace Ring < Language(".ring") ; location &= "https://github.com/nicklockwood/Ring" & "https://ring-lang.net/" & "https://en.wikipedia.org/wiki/Ring_(programming_language)" + namespace Seed7 < Language(".sd7") ; location &= "https://github.com/ThomasMertes/seed7" & "https://en.wikipedia.org/wiki/Seed7" + namespace Library < Language(".s7i") + namespace Starlark < Language(".star") ; location &= "https://github.com/bazelbuild/starlark" & "https://en.wikipedia.org/wiki/Starlark_(programming_language)" + namespace Toit < Language(".toit") ; location &= "https://github.com/toitlang/toit" & "https://toitlang.org/" + namespace Typst < Language(".typ") ; location &= "https://github.com/typst/typst" & "https://typst.app/" & "https://en.wikipedia.org/wiki/Typst" + namespace Uxntal | "Uxn" < Language(".tal") ; location &= "https://git.sr.ht/~rabbits/uxn" & "https://wiki.xxiivv.com/site/uxntal.html" + namespace ROM < Language(".rom") + namespace Vala < Language(".vala") ; location &= "https://gitlab.gnome.org/GNOME/vala" & "https://vala.dev/" & "https://en.wikipedia.org/wiki/Vala_(programming_language)" + namespace Interface < Language(".vapi") + namespace Verona < Language() ; location &= "https://github.com/nicklockwood/verona" & "https://en.wikipedia.org/wiki/Project_Verona" + namespace Wing < Language(".w") ; location &= "https://github.com/winglang/wing" & "https://www.winglang.io/" + + // --- New entries: Theorem Provers & SAT/SMT Solvers --- + namespace Boogie < Language(".bpl") ; location &= "https://github.com/boogie-org/boogie" + namespace CADP | "Construction and Analysis of Distributed Processes" < Language(".lotos" | ".lnt") ; location &= "https://cadp.inria.fr/" & "https://en.wikipedia.org/wiki/Construction_and_Analysis_of_Distributed_Processes" + namespace CPAchecker < Tool ; location &= "https://github.com/sosy-lab/cpachecker" & "https://en.wikipedia.org/wiki/CPAchecker" + namespace CPNTools | "CPN Tools" < Language(".cpn") ; location &= "https://cpntools.org/" & "https://en.wikipedia.org/wiki/CPN_Tools" + namespace CryptoMiniSat < Language(".cnf") ; location &= "https://github.com/msoos/cryptominisat" + namespace EasyCrypt < Language(".ec") ; location &= "https://github.com/EasyCrypt/easycrypt" + namespace FDR | "Failures-Divergences Refinement" < Language(".csp") ; location &= "https://cocotec.io/fdr/" & "https://en.wikipedia.org/wiki/FDR_(software)" + namespace FramaC | "Frama-C" < Tool ; location &= "https://github.com/Frama-C/Frama-C-snapshot" & "https://frama-c.com/" & "https://en.wikipedia.org/wiki/Frama-C" + namespace Glucose < Language(".cnf") ; location &= "https://github.com/audemard/glucose" + namespace KeY < Language(".key") ; location &= "https://github.com/KeYProject/key" & "https://en.wikipedia.org/wiki/KeY" + namespace Kissat < Language(".cnf") ; location &= "https://github.com/arminbiere/kissat" + namespace KLEE < Tool ; location &= "https://github.com/klee/klee" & "https://klee-se.org/" + namespace LCF | "Logic for Computable Functions" < Language() ; location &= "https://en.wikipedia.org/wiki/Logic_for_Computable_Functions" + namespace Lingeling < Language(".cnf") ; location &= "https://github.com/arminbiere/lingeling" + namespace LiquidHaskell | "Liquid Haskell" < Language(".hs") ; location &= "https://github.com/ucsd-progsys/liquidhaskell" & "https://en.wikipedia.org/wiki/Liquid_Haskell" + namespace mCRL2 < Language(".mcrl2" | ".mcf") ; location &= "https://github.com/mCRL2org/mCRL2" & "https://www.mcrl2.org/" + namespace NuSMV < Language(".smv") ; location &= "https://nusmv.fbk.eu/" & "https://en.wikipedia.org/wiki/NuSMV" + namespace nuXmv < Language(".smv") ; location &= "https://nuxmv.fbk.eu/" + namespace OpenSMT < Language(".smt2") ; location &= "https://github.com/usi-verification-and-security/opensmt" + namespace Princess < Language(".smt2" | ".pri") ; location &= "https://github.com/uuverifiers/princess" + namespace ProB < Tool ; location &= "https://github.com/hhu-stups/prob2_ui" & "https://prob.hhu.de/" + namespace SeaHorn < Tool ; location &= "https://github.com/seahorn/seahorn" & "https://seahorn.github.io/" + namespace SETHEO < Language(".p") ; location &= "https://github.com/theoremprover-museum/SETHEO" + namespace SMACK < Tool ; location &= "https://github.com/smackers/smack" + namespace SMTInterpol < Language(".smt2") ; location &= "https://github.com/ultimate-pa/smtinterpol" + namespace SPARK | "SPARK Ada" < Language(".ads" | ".adb") ; location &= "https://github.com/AdaCore/spark2014" & "https://www.adacore.com/about-spark" + namespace Stainless < Language(".scala") ; location &= "https://github.com/epfl-lara/stainless" & "https://stainless.epfl.ch/" + namespace Storm < Tool ; location &= "https://github.com/moves-rwth/storm" & "https://www.stormchecker.org/" + namespace STP < Language(".smt2" | ".stp") ; location &= "https://github.com/stp/stp" + namespace SymbiYosys < Language(".sby") ; location &= "https://github.com/YosysHQ/sby" + namespace TAPAAL < Language(".tapn") ; location &= "https://github.com/TAPAAL/tapaal-gui" & "https://en.wikipedia.org/wiki/TAPAAL_Model_Checker" + namespace Twee < Language(".p") ; location &= "https://github.com/nick8325/twee" + namespace UPPAAL < Language(".xta") ; location &= "https://uppaal.org/" & "https://en.wikipedia.org/wiki/Uppaal_Model_Checker" + namespace Varisat < Language(".cnf") ; location &= "https://github.com/jix/varisat" + namespace VeriFast < Tool ; location &= "https://github.com/verifast/verifast" + namespace Viper | "Viper Verification" < Language(".vpr") ; location &= "https://github.com/viperproject/silver" & "https://www.pm.inf.ethz.ch/research/viper.html" + namespace Yices | "Yices 2" < Language(".smt2" | ".ys") ; location &= "https://github.com/SRI-CSL/yices2" & "https://yices.csl.sri.com/" + + // --- New entries: Esoteric Languages --- + namespace BinaryLambdaCalculus | "Binary Lambda Calculus" < Language(".blc") ; location &= "https://github.com/tromp/AIT" & "https://en.wikipedia.org/wiki/Binary_lambda_calculus" + namespace Deadfish < Language(".df") ; location &= "https://esolangs.org/wiki/Deadfish" + namespace Dis < Language(".dis") ; location &= "https://esolangs.org/wiki/Dis" + namespace FALSE < Language(".fal") ; location &= "https://esolangs.org/wiki/FALSE" & "https://en.wikipedia.org/wiki/FALSE_(programming_language)" + namespace Funciton < Language(".fct") ; location &= "https://github.com/Timwi/Funciton" & "https://esolangs.org/wiki/Funciton" + namespace Funge98 | "Funge-98" < Language(".b98") ; location &= "https://github.com/catseye/Funge-98" & "https://esolangs.org/wiki/Funge-98" + namespace Grass < Language(".w") ; location &= "https://esolangs.org/wiki/Grass" + namespace Hexagony < Language(".hxg") ; location &= "https://github.com/m-ender/hexagony" & "https://esolangs.org/wiki/Hexagony" + namespace INTERCAL < Language(".i") ; location &= "https://gitlab.com/esr/intercal" & "https://en.wikipedia.org/wiki/INTERCAL" + namespace Iota < Language(".iota") ; location &= "https://esolangs.org/wiki/Iota" & "https://en.wikipedia.org/wiki/Iota_and_Jot" + namespace Jot < Language(".jot") ; location &= "https://esolangs.org/wiki/Jot" & "https://en.wikipedia.org/wiki/Iota_and_Jot" + namespace JSFuck < Language(".js") ; location &= "https://github.com/aemkei/jsfuck" & "https://en.wikipedia.org/wiki/JSFuck" + namespace LazyK | "Lazy K" < Language(".lazy") ; location &= "https://github.com/irori/lazyk" & "https://esolangs.org/wiki/Lazy_K" + namespace Ook < Language(".ook") ; location &= "https://esolangs.org/wiki/Ook!" + namespace Underload < Language(".ul") ; location &= "https://esolangs.org/wiki/Underload" + namespace Unlambda < Language(".unl") ; location &= "https://esolangs.org/wiki/Unlambda" & "https://en.wikipedia.org/wiki/Unlambda" + namespace UniversalLambda | "Universal Lambda" < Language(".lam") ; location &= "https://esolangs.org/wiki/Universal_Lambda" + namespace Wierd < Language(".wd") ; location &= "https://esolangs.org/wiki/Wierd" + namespace Zot < Language(".zot") ; location &= "https://esolangs.org/wiki/Zot" & "https://en.wikipedia.org/wiki/Iota_and_Jot" + + // --- New entries: Type Theory Implementations --- + namespace cctt | "Cartesian Cubical Type Theory" < Language(".cctt") ; location &= "https://github.com/AndrasKovacs/cctt" + namespace cooltt < Language(".cooltt") ; location &= "https://github.com/RedPRL/cooltt" + namespace Pict < Language(".pi") ; location &= "https://en.wikipedia.org/wiki/Pict_(programming_language)" + namespace piforall | "pi-forall" < Language(".pi") ; location &= "https://github.com/sweirich/pi-forall" + namespace Pure < Language(".pure") ; location &= "https://github.com/agraef/pure-lang" & "https://en.wikipedia.org/wiki/Pure_(programming_language)" + namespace RedPRL < Language(".prl") ; location &= "https://github.com/RedPRL/sml-redprl" & "https://redprl.org/" + namespace SOTT | "Simplified Observational Type Theory" < Language(".sott") ; location &= "https://github.com/bobatkey/sott" + namespace setoidtt | "Setoid Type Theory" < Language(".stt") ; location &= "https://github.com/AndrasKovacs/setoidtt" + namespace trebor < Language(".treb") ; location &= "https://github.com/Guest0x0/trebor" + + // --- New entries: Interaction Nets --- + namespace Inpla < Language(".in") ; location &= "https://github.com/inpla/inpla" + namespace LambdaLisp < Language(".cl") ; location &= "https://github.com/woodrush/lambdalisp" + + // --- New entries: Computer Algebra Systems --- + namespace Axiom < Language(".spad" | ".input") ; location &= "https://github.com/daly/axiom" & "https://en.wikipedia.org/wiki/Axiom_(computer_algebra_system)" + namespace Cadabra < Language(".cdb" | ".cnb") ; location &= "https://github.com/kpeeters/cadabra2" & "https://en.wikipedia.org/wiki/Cadabra_(computer_program)" + namespace CoCoA < Language(".cpkg5") ; location &= "https://github.com/cocoa-official/CoCoALib" & "https://en.wikipedia.org/wiki/CoCoA" + namespace FLINT | "Fast Library for Number Theory" < Library ; location &= "https://github.com/flintlib/flint" & "https://en.wikipedia.org/wiki/Fast_Library_for_Number_Theory" + namespace FORM < Language(".frm") ; location &= "https://github.com/form-dev/form" & "https://en.wikipedia.org/wiki/FORM_(symbolic_manipulation_system)" + namespace FriCAS < Language(".spad" | ".input") ; location &= "https://github.com/fricas/fricas" & "https://en.wikipedia.org/wiki/FriCAS" + namespace GiNaC < Library ; location &= "https://en.wikipedia.org/wiki/GiNaC" + namespace Macaulay2 < Language(".m2") ; location &= "https://github.com/Macaulay2/M2" & "https://en.wikipedia.org/wiki/Macaulay2" + namespace Magma | "Magma CAS" < Language(".m" | ".mag") ; location &= "http://magma.maths.usyd.edu.au/magma/" & "https://en.wikipedia.org/wiki/Magma_(computer_algebra_system)" + namespace PARIGP | "PARI/GP" < Language(".gp") ; location &= "https://pari.math.u-bordeaux.fr/" & "https://en.wikipedia.org/wiki/PARI/GP" + namespace Polymake < Language(".poly") ; location &= "https://github.com/polymake/polymake" & "https://en.wikipedia.org/wiki/Polymake" + namespace REDUCE < Language(".red") ; location &= "https://github.com/reduce-algebra/reduce-algebra" & "https://en.wikipedia.org/wiki/Reduce_(computer_algebra_system)" + namespace Singular < Language(".sing") ; location &= "https://github.com/Singular/Singular" & "https://en.wikipedia.org/wiki/Singular_(software)" + namespace SymEngine < Library ; location &= "https://github.com/symengine/symengine" + namespace Xcas | Giac < Language() ; location &= "https://en.wikipedia.org/wiki/Xcas" + namespace Yacas < Language(".ys") ; location &= "https://github.com/grzegorzmazur/yacas" & "https://en.wikipedia.org/wiki/Yacas" + + // --- New entries: Music & Audio Programming --- + namespace SuperCollider < Language(".scd" | ".sc") ; location &= "https://github.com/supercollider/supercollider" & "https://supercollider.github.io/" & "https://en.wikipedia.org/wiki/SuperCollider" + namespace Csound < Language(".csd" | ".orc" | ".sco") ; location &= "https://github.com/csound/csound" & "https://csound.com/" & "https://en.wikipedia.org/wiki/Csound" + namespace SonicPi | "Sonic Pi" < Language(".rb") ; location &= "https://github.com/sonic-pi-net/sonic-pi" & "https://sonic-pi.net/" & "https://en.wikipedia.org/wiki/Sonic_Pi" + namespace TidalCycles | "Tidal Cycles" < Language(".hs") ; location &= "https://github.com/tidalcycles/Tidal" & "https://tidalcycles.org/" & "https://en.wikipedia.org/wiki/TidalCycles" + namespace Faust < Language(".dsp") ; location &= "https://github.com/grame-cncm/faust" & "https://faust.grame.fr/" & "https://en.wikipedia.org/wiki/FAUST_(programming_language)" + namespace Extempore < Language(".xtm") ; location &= "https://github.com/digego/extempore" & "https://extemporelang.github.io/" & "https://en.wikipedia.org/wiki/Extempore_(software)" + + // --- New entries: Smart Contract & Blockchain Languages --- + namespace Cairo < Language(".cairo") ; location &= "https://github.com/starkware-libs/cairo" & "https://www.cairo-lang.org/" + namespace Clarity < Language(".clar") ; location &= "https://github.com/stacks-network/stacks-core" & "https://clarity-lang.org/" + namespace Teal | "Transaction Execution Approval Language" < Language(".teal") ; location &= "https://github.com/algorand/go-algorand" & "https://developer.algorand.org/docs/get-details/dapps/avm/teal/" + namespace Plutus < Language(".hs") ; location &= "https://github.com/IntersectMBO/plutus" & "https://en.wikipedia.org/wiki/Cardano_(blockchain_platform)" + namespace Marlowe < Language(".marlowe") ; location &= "https://github.com/input-output-hk/marlowe-cardano" & "https://marlowe.iohk.io/" + namespace Ink! < Language(".rs") ; location &= "https://github.com/use-ink/ink" & "https://use.ink/" + + // --- New entries: Array & Scientific Languages --- + namespace J < Language(".ijs") ; location &= "https://github.com/jsoftware/jsource" & "https://www.jsoftware.com/" & "https://en.wikipedia.org/wiki/J_(programming_language)" + namespace K < Language(".k") ; location &= "https://en.wikipedia.org/wiki/K_(programming_language)" + namespace Q | "Q/kdb+" < Language(".q") ; location &= "https://code.kx.com/q/" & "https://en.wikipedia.org/wiki/Q_(programming_language_from_Kx_Systems)" + + // --- New entries: Logic Programming --- + namespace Prolog < Language(".pl" | ".pro") ; location &= "https://en.wikipedia.org/wiki/Prolog" + namespace SWIProlog | "SWI-Prolog" < Language(".pl") ; location &= "https://github.com/SWI-Prolog/swipl-devel" & "https://www.swi-prolog.org/" & "https://en.wikipedia.org/wiki/SWI-Prolog" + namespace SICStus | "SICStus Prolog" < Language(".pl") ; location &= "https://sicstus.sics.se/" & "https://en.wikipedia.org/wiki/SICStus_Prolog" + namespace Curry < Language(".curry") ; location &= "https://github.com/curry-language" & "https://curry-lang.org/" & "https://en.wikipedia.org/wiki/Curry_(programming_language)" + + // --- New entries: Document & Markup Languages --- + namespace AsciiDoc < Language(".adoc" | ".asciidoc") ; location &= "https://github.com/asciidoc/asciidoc-py" & "https://asciidoc.org/" & "https://en.wikipedia.org/wiki/AsciiDoc" + namespace Djot < Language(".dj") ; location &= "https://github.com/jgm/djot" & "https://djot.net/" + namespace Org | "Org Mode" < Language(".org") ; location &= "https://git.savannah.gnu.org/cgit/emacs/org-mode.git/" & "https://orgmode.org/" & "https://en.wikipedia.org/wiki/Org-mode" + namespace Textile < Language(".textile") ; location &= "https://github.com/textile/textile-lang" & "https://en.wikipedia.org/wiki/Textile_(markup_language)" + + // --- New entries: 3D / CAD / Visual --- + namespace OpenSCAD < Language(".scad") ; location &= "https://github.com/openscad/openscad" & "https://openscad.org/" & "https://en.wikipedia.org/wiki/OpenSCAD" + namespace SVG | "Scalable Vector Graphics" < Language(".svg") ; location &= "https://www.w3.org/Graphics/SVG/" & "https://en.wikipedia.org/wiki/SVG" + namespace PDF | "Portable Document Format" < Language(".pdf") ; location &= "https://en.wikipedia.org/wiki/PDF" + + // --- New entries: General-Purpose Languages (notable missing) --- + namespace Tcl | "Tool Command Language" < Language(".tcl") ; location &= "https://github.com/tcltk/tcl" & "https://www.tcl-lang.org/" & "https://en.wikipedia.org/wiki/Tcl" + namespace Tk < Language(".tcl") ; location &= "https://en.wikipedia.org/wiki/Tk_(software)" + namespace Io < Language(".io") ; location &= "https://github.com/IoLanguage/io" & "https://iolanguage.org/" & "https://en.wikipedia.org/wiki/Io_(programming_language)" + namespace Icon < Language(".icn") ; location &= "https://github.com/uniconproject/unicon" & "https://en.wikipedia.org/wiki/Icon_(programming_language)" + namespace Rebol < Language(".r" | ".reb") ; location &= "http://www.rebol.com/" & "https://en.wikipedia.org/wiki/Rebol" + namespace Self < Language(".self") ; location &= "https://github.com/nicklockwood/SelfProject" & "https://selflanguage.org/" & "https://en.wikipedia.org/wiki/Self_(programming_language)" + namespace Fantom < Language(".fan") ; location &= "https://github.com/nicklockwood/fantom" & "https://fantom.org/" & "https://en.wikipedia.org/wiki/Fantom_(programming_language)" + namespace Squirrel < Language(".nut") ; location &= "http://www.squirrel-lang.org/" & "https://en.wikipedia.org/wiki/Squirrel_(programming_language)" + namespace Euphoria < Language(".ex" | ".exw") ; location &= "https://openeuphoria.org/" & "https://en.wikipedia.org/wiki/Euphoria_(programming_language)" + namespace Harbour < Language(".prg") ; location &= "https://github.com/harbour/core" & "https://harbour.github.io/" & "https://en.wikipedia.org/wiki/Harbour_(programming_language)" + namespace Pawn < Language(".p" | ".pwn") ; location &= "https://github.com/compuphase/pawn" & "https://en.wikipedia.org/wiki/Pawn_(scripting_language)" + + // --- New entries: Cloud / Infrastructure --- + namespace Bicep < Language(".bicep") ; location &= "https://github.com/Azure/bicep" & "https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/" + namespace Pulumi < Language(".ts" | ".py" | ".go") ; location &= "https://github.com/pulumi/pulumi" & "https://www.pulumi.com/" & "https://en.wikipedia.org/wiki/Pulumi" + + // --- New entries: Quantum Computing --- + namespace Qiskit < Language(".py") ; location &= "https://github.com/Qiskit/qiskit" & "https://www.ibm.com/quantum/qiskit" & "https://en.wikipedia.org/wiki/Qiskit" + namespace StrawberryFields | "Strawberry Fields" < Language(".py") ; location &= "https://github.com/XanaduAI/strawberryfields" & "https://strawberryfields.ai/" + + // --- New entries: Database Query Languages --- + namespace Gremlin < Language(".groovy") ; location &= "https://github.com/apache/tinkerpop" & "https://tinkerpop.apache.org/" & "https://en.wikipedia.org/wiki/Gremlin_(query_language)" + namespace AQL | "ArangoDB Query Language" < Language(".aql") ; location &= "https://github.com/arangodb/arangodb" & "https://www.arangodb.com/" + + // --- New entries: Image/Media Formats --- + namespace JPEG < Language(".jpg" | ".jpeg") ; location &= "https://en.wikipedia.org/wiki/JPEG" + namespace PNG | "Portable Network Graphics" < Language(".png") ; location &= "https://en.wikipedia.org/wiki/PNG" + namespace GIF | "Graphics Interchange Format" < Language(".gif") ; location &= "https://en.wikipedia.org/wiki/GIF" + namespace WebP < Language(".webp") ; location &= "https://en.wikipedia.org/wiki/WebP" + namespace TIFF | "Tagged Image File Format" < Language(".tiff" | ".tif") ; location &= "https://en.wikipedia.org/wiki/TIFF" + namespace BMP | "Bitmap" < Language(".bmp") ; location &= "https://en.wikipedia.org/wiki/BMP_file_format" + + // --- New entries: Term Rewriting Systems --- + namespace Stratego < Language(".str") ; location &= "https://github.com/metaborg/stratego" & "https://en.wikipedia.org/wiki/Stratego/XT" + namespace Stratego2 < Language(".str2") + namespace Tom < Language(".tom") ; location &= "https://github.com/rewriting/tom" & "https://en.wikipedia.org/wiki/Tom_(pattern_matching_language)" + namespace egglog < Language(".egg") ; location &= "https://github.com/egraphs-good/egglog" + + // --- New entries: Graph Transformation Languages --- + namespace GrGen | "GrGen.NET" < Language(".gm") ; location &= "https://github.com/ejaku/grgen" & "https://en.wikipedia.org/wiki/GrGen" + namespace Rules < Language(".grg") + namespace Scripts < Language(".grs") + namespace Henshin < Language(".henshin") ; location &= "https://github.com/eclipse-henshin/henshin" + namespace Diagram < Language(".henshin_diagram") + namespace eMoflon | "eMoflon::IBeX" < Tool ; location &= "https://github.com/eMoflon/emoflon-ibex" + namespace Porgy < Tool ; location &= "https://github.com/bpinaud/Porgy" + + // --- New entries: Categorical Query Language --- + namespace CQL | "Categorical Query Language" < Language(".cql") ; location &= "https://github.com/CategoricalData/CQL" + + // --- New entries: Dependent Type Implementations --- + namespace MiniTT | "Mini-TT" < Language(".minitt") ; location &= "https://github.com/owo-lang/minitt-rs" + namespace smalltt < Language(".stt") ; location &= "https://github.com/AndrasKovacs/smalltt" + namespace SpartanTT | "Spartan Type Theory" < Tool ; location &= "https://github.com/andrejbauer/spartan-type-theory" + + // --- New entries: Effect Systems --- + namespace Frank < Language(".fk") ; location &= "https://github.com/frank-lang/frank" + namespace Links < Language(".links") ; location &= "https://github.com/links-lang/links" + namespace Helium < Language(".hs") ; location &= "https://github.com/Helium4Haskell/helium" + + // --- New entries: Abstract Interpretation --- + namespace Mopsa < Tool ; location &= "https://gitlab.com/mopsa/mopsa-analyzer" + + // --- New entries: Quantum Assembly --- + namespace Blackbird < Language(".xbb") ; location &= "https://github.com/XanaduAI/blackbird" + namespace Quirk < Tool ; location &= "https://github.com/Strilanc/Quirk" + + // --- New entries: Notable Missing General Languages --- + namespace Raku | "Perl 6" < Language(".raku") ; location &= "https://github.com/rakudo/rakudo" & "https://raku.org/" & "https://en.wikipedia.org/wiki/Raku_(programming_language)" + namespace Module < Language(".rakumod") + namespace Test < Language(".rakutest") + namespace Simula < Language(".sim") ; location &= "https://en.wikipedia.org/wiki/Simula" + namespace Modelica < Language(".mo") ; location &= "https://github.com/modelica" & "https://modelica.org/" & "https://en.wikipedia.org/wiki/Modelica" + namespace Logtalk < Language(".lgt") ; location &= "https://github.com/LogtalkDotOrg/logtalk3" & "https://logtalk.org/" & "https://en.wikipedia.org/wiki/Logtalk" + namespace Loader < Language(".loader") + + // --- New entries: Rule Engines & Expert Systems --- + namespace CLIPS < Language(".clp") ; location &= "https://sourceforge.net/projects/clipsrules/" & "https://en.wikipedia.org/wiki/CLIPS" + namespace Drools < Language(".drl") ; location &= "https://github.com/apache/incubator-kie-drools" & "https://en.wikipedia.org/wiki/Drools" + namespace Inform7 | "Inform 7" < Language(".ni") ; location &= "https://github.com/ganelson/inform" & "https://inform7.com/" & "https://en.wikipedia.org/wiki/Inform" + namespace Extension < Language(".i7x") + + // --- New entries: Biological Modeling Languages --- + namespace BNGL | "BioNetGen Language" < Language(".bngl") ; location &= "https://github.com/RuleWorld/bionetgen" & "https://bionetgen.org/" + namespace Kappa < Language(".ka") ; location &= "https://github.com/Kappa-Dev/KaSim" & "https://kappalanguage.org/" + namespace NeuroML < Language(".nml") ; location &= "https://github.com/NeuroML" & "https://neuroml.org/" & "https://en.wikipedia.org/wiki/NeuroML" + namespace LEMS < Language(".xml") ; location &= "https://github.com/LEMS/jLEMS" & "https://en.wikipedia.org/wiki/LEMS" + namespace NEURON < Language(".hoc") ; location &= "https://github.com/neuronsimulator/nrn" & "https://www.neuron.yale.edu/" & "https://en.wikipedia.org/wiki/NEURON" + namespace Mechanism < Language(".mod") + namespace SEDML | "SED-ML" < Language(".sedml") ; location &= "https://sed-ml.org/" & "https://en.wikipedia.org/wiki/SED-ML" + namespace SBGN | "Systems Biology Graphical Notation" < Language(".sbgn") ; location &= "https://sbgn.github.io/sbgn/" & "https://en.wikipedia.org/wiki/Systems_Biology_Graphical_Notation" + + // --- New entries: Simulation Languages --- + namespace OMNeTpp | "OMNeT++" < Language(".ned") ; location &= "https://github.com/omnetpp/omnetpp" & "https://omnetpp.org/" & "https://en.wikipedia.org/wiki/OMNeT%2B%2B" + namespace INI < Language(".ini") + namespace GPSS | "General Purpose Simulation System" < Language(".gps") ; location &= "https://en.wikipedia.org/wiki/GPSS" + + // --- New entries: Semantic Web & Ontology --- + namespace SHACL | "Shapes Constraint Language" < Language(".shacl") ; location &= "https://www.w3.org/TR/shacl/" & "https://en.wikipedia.org/wiki/SHACL" + namespace ShEx | "Shape Expressions" < Language(".shex") ; location &= "https://github.com/shexSpec/shex" & "https://shex.io/" + namespace SysML < Language(".sysml") ; location &= "https://sysml.org/" & "https://en.wikipedia.org/wiki/Systems_modeling_language" + namespace OCL | "Object Constraint Language" < Language(".ocl") ; location &= "https://en.wikipedia.org/wiki/Object_Constraint_Language" + + // --- New entries: Constraint Programming --- + namespace ECLiPSeCLP | "ECLiPSe-CLP" < Language(".ecl") ; location &= "https://eclipseclp.org/" & "https://en.wikipedia.org/wiki/ECLiPSe" + + // --- New entries: Hardware Description --- + namespace Silice < Language(".si") ; location &= "https://github.com/sylefeb/Silice" + namespace Lola < Language(".lola") ; location &= "https://en.wikipedia.org/wiki/Lola_(programming_language)" + + // --- New entries: EDA Formats --- + namespace EDIF | "Electronic Design Interchange Format" < Language(".edf" | ".edif") ; location &= "https://en.wikipedia.org/wiki/EDIF" + namespace SPICE < Language(".sp" | ".cir") ; location &= "https://en.wikipedia.org/wiki/SPICE" + namespace HSPICE < Language(".hsp") + namespace GDSII | "Graphic Data System II" < Language(".gds") ; location &= "https://en.wikipedia.org/wiki/GDSII" + namespace OASIS | "Open Artwork System Interchange Standard" < Language(".oas") ; location &= "https://en.wikipedia.org/wiki/Open_Artwork_System_Interchange_Standard" + namespace Liberty < Language(".lib") ; location &= "https://en.wikipedia.org/wiki/Liberty_(EDA)" + namespace LEF | "Library Exchange Format" < Language(".lef") ; location &= "https://en.wikipedia.org/wiki/Library_Exchange_Format" + namespace DEF | "Design Exchange Format" < Language(".def") ; location &= "https://en.wikipedia.org/wiki/Design_Exchange_Format" + + // --- New entries: Smart Contract / Blockchain Languages --- + namespace Sway < Language(".sw") ; location &= "https://github.com/FuelLabs/sway" & "https://docs.fuel.network/docs/sway/" + namespace Aiken < Language(".ak") ; location &= "https://github.com/aiken-lang/aiken" & "https://aiken-lang.org/" + namespace Fe < Language(".fe") ; location &= "https://github.com/ethereum/fe" & "https://fe-lang.org/" + namespace Motoko < Language(".mo") ; location &= "https://github.com/dfinity/motoko" & "https://internetcomputer.org/" + namespace Tact < Language(".tact") ; location &= "https://github.com/tact-lang/tact" & "https://tact-lang.org/" + namespace FunC < Language(".fc") ; location &= "https://github.com/ton-blockchain/ton" & "https://docs.ton.org/" + + // --- New entries: Semantic Web / Data Languages --- + namespace Turtle | "Terse RDF Triple Language" < Language(".ttl") ; location &= "https://www.w3.org/TR/turtle/" & "https://en.wikipedia.org/wiki/Turtle_(syntax)" + + // --- New entries: Array / Scientific Languages --- + namespace Klong < Language(".kg") ; location &= "https://t3x.org/klong/" + namespace Numbat < Language(".nbt") ; location &= "https://github.com/sharkdp/numbat" & "https://numbat.dev/" + namespace Frink < Language(".frink") ; location &= "https://frinklang.org/" + + // --- New entries: Logic / Constraint Programming --- + namespace Ciao < Language(".pl") ; location &= "https://github.com/ciao-lang/ciao" & "https://ciao-lang.org/" & "https://en.wikipedia.org/wiki/Ciao_(programming_language)" + namespace Oz | Mozart < Language(".oz") ; location &= "https://github.com/mozart/mozart2" & "http://mozart2.org/" & "https://en.wikipedia.org/wiki/Oz_(programming_language)" + namespace ELPI | "Embeddable Lambda Prolog Interpreter" < Language(".elpi") ; location &= "https://github.com/LPCIC/elpi" + + // --- New entries: Cloud / Policy Languages --- + namespace KCL | "Kubernetes Configuration Language" < Language(".k") ; location &= "https://github.com/kcl-lang/kcl" & "https://www.kcl-lang.io/" + namespace Rego < Language(".rego") ; location &= "https://github.com/open-policy-agent/opa" & "https://www.openpolicyagent.org/" + namespace Cedar < Language(".cedar") ; location &= "https://github.com/cedar-policy/cedar" & "https://www.cedarpolicy.com/" + + // --- New entries: Network Programming --- + namespace P4 | "Programming Protocol-independent Packet Processors" < Language(".p4") ; location &= "https://github.com/p4lang/p4c" & "https://p4.org/" & "https://en.wikipedia.org/wiki/P4_(programming_language)" + + // --- New entries: Build System Languages --- + namespace CMake < Language(".cmake") ; location &= "https://github.com/Kitware/CMake" & "https://cmake.org/" & "https://en.wikipedia.org/wiki/CMake" + namespace Meson < Language(".meson") ; location &= "https://github.com/mesonbuild/meson" & "https://mesonbuild.com/" & "https://en.wikipedia.org/wiki/Meson_(software)" + + // --- New entries: Parser / Grammar Languages --- + namespace Lark < Language(".lark") ; location &= "https://github.com/lark-parser/lark" + + // --- New entries: General-Purpose Languages --- + namespace Jai < Language(".jai") ; location &= "https://jai.community/" & "https://en.wikipedia.org/wiki/Jai_(programming_language)" + namespace Eiffel < Language(".e") ; location &= "https://github.com/EiffelSoftware/EiffelStudio" & "https://www.eiffel.org/" & "https://en.wikipedia.org/wiki/Eiffel_(programming_language)" + namespace GDScript | "Godot Script" < Language(".gd") ; location &= "https://github.com/godotengine/godot" & "https://godotengine.org/" & "https://en.wikipedia.org/wiki/Godot_(game_engine)" + namespace LFE | "Lisp Flavoured Erlang" < Language(".lfe") ; location &= "https://github.com/lfe/lfe" & "https://lfe.io/" & "https://en.wikipedia.org/wiki/LFE_(programming_language)" + namespace Hoon < Language(".hoon") ; location &= "https://github.com/urbit/urbit" & "https://docs.urbit.org/language/hoon" & "https://en.wikipedia.org/wiki/Urbit" + namespace Wyvern < Language(".wyv") ; location &= "https://github.com/wyvernlang/wyvern" & "https://wyvernlang.github.io/" + namespace Lox < Language(".lox") ; location &= "https://github.com/munificent/craftinginterpreters" & "https://craftinginterpreters.com/" + namespace Amber < Language(".ab") ; location &= "https://github.com/amber-lang/amber" & "https://amber-lang.com/" + namespace Bel < Language(".bel") ; location &= "https://paulgraham.com/bel.html" + + // --- New entries: Ontology & Knowledge Representation Languages --- + namespace OWL | "Web Ontology Language" < Language(".owl") ; location &= "https://github.com/owlcs/owlapi" & "https://www.w3.org/OWL/" & "https://en.wikipedia.org/wiki/Web_Ontology_Language" + namespace ManchesterSyntax | "Manchester OWL Syntax" < Language(".omn") ; location &= "https://www.w3.org/TR/owl2-manchester-syntax/" + namespace FunctionalSyntax < Language(".ofn") + namespace RDF | "Resource Description Framework" < Language(".rdf") ; location &= "https://www.w3.org/RDF/" & "https://en.wikipedia.org/wiki/Resource_Description_Framework" + namespace RDFS | "RDF Schema" < Language(".rdf") ; location &= "https://www.w3.org/TR/rdf-schema/" & "https://en.wikipedia.org/wiki/RDF_Schema" + namespace N3 | "Notation3" < Language(".n3") ; location &= "https://w3c.github.io/N3/spec/" & "https://en.wikipedia.org/wiki/Notation3" + namespace NTriples | "N-Triples" < Language(".nt") ; location &= "https://www.w3.org/TR/n-triples/" & "https://en.wikipedia.org/wiki/N-Triples" + namespace NQuads | "N-Quads" < Language(".nq") ; location &= "https://www.w3.org/TR/n-quads/" + namespace SKOS | "Simple Knowledge Organization System" < Language(".rdf") ; location &= "https://www.w3.org/TR/skos-reference/" & "https://en.wikipedia.org/wiki/Simple_Knowledge_Organization_System" + namespace OBO | "OBO Format" < Language(".obo") ; location &= "https://github.com/owlcollab/oboformat" & "http://obofoundry.org/" & "https://en.wikipedia.org/wiki/Open_Biomedical_Ontologies" + namespace KIF | "Knowledge Interchange Format" < Language(".kif") ; location &= "http://www-ksl.stanford.edu/knowledge-sharing/kif/" & "https://en.wikipedia.org/wiki/Knowledge_Interchange_Format" + namespace CommonLogic | "Common Logic" < Language(".cl") ; location &= "https://en.wikipedia.org/wiki/Common_Logic" + namespace CLIF | "Common Logic Interchange Format" < Language(".clif") + namespace CycL < Language(".cycl") ; location &= "https://github.com/white-flame/clyc" & "https://en.wikipedia.org/wiki/CycL" + namespace Ontolingua < Language(".kif") ; location &= "http://www.ksl.stanford.edu/software/ontolingua/" & "https://en.wikipedia.org/wiki/Ontolingua" + + // --- New entries: Formal Specification & Model Transformation --- + namespace AADL | "Architecture Analysis & Design Language" < Language(".aadl") ; location &= "https://github.com/osate/osate2" & "https://en.wikipedia.org/wiki/Architecture_Analysis_%26_Design_Language" + namespace MARTE | "Modeling and Analysis of Real Time and Embedded systems" < Language(".uml") ; location &= "https://www.omg.org/spec/MARTE/" & "https://en.wikipedia.org/wiki/Modeling_and_Analysis_of_Real_Time_and_Embedded_systems" + namespace QVT | "Query/View/Transformation" < Language(".qvto") ; location &= "https://en.wikipedia.org/wiki/QVT" + namespace QVTr | "QVT Relations" < Language(".qvtr") + namespace ATL | "ATLAS Transformation Language" < Language(".atl") ; location &= "https://github.com/eclipse-atl/atl" & "https://en.wikipedia.org/wiki/ATLAS_Transformation_Language" + namespace Epsilon < Language(".eol") ; location &= "https://github.com/eclipse-epsilon/epsilon" & "https://eclipse.dev/epsilon/" + namespace ETL | "Epsilon Transformation Language" < Language(".etl") + namespace EVL | "Epsilon Validation Language" < Language(".evl") + namespace EGX | "Epsilon Generation Language" < Language(".egx") + + // --- New entries: Logic Programming (additional) --- + namespace LambdaProlog | "Lambda Prolog" < Language(".mod") ; location &= "https://github.com/teyjus/teyjus" & "https://en.wikipedia.org/wiki/%CE%9BProlog" + namespace Signature < Language(".sig") + namespace miniKanren < Language(".scm") ; location &= "https://github.com/miniKanren" & "https://minikanren.org/" & "https://en.wikipedia.org/wiki/MiniKanren" + namespace cKanren < Language(".rkt") ; location &= "https://github.com/calvis/cKanren" + + // --- New entries: Controlled Natural Languages --- + namespace ACE | "Attempto Controlled English" < Language(".ace") ; location &= "https://github.com/Attempto/APE" & "https://attempto.ifi.uzh.ch/" & "https://en.wikipedia.org/wiki/Attempto_Controlled_English" + namespace PENG | "Processable English" < Language ; location &= "https://en.wikipedia.org/wiki/Controlled_natural_language" + + // --- New entries: Biological Modeling Tools --- + namespace BioModelAnalyzer < Tool ; location &= "https://github.com/microsoft/BioModelAnalyzer" + namespace BioPEPA | "Bio-PEPA" < Language(".biopepa") ; location &= "https://github.com/Bio-PEPA/Bio-PEPA" & "https://homepages.inf.ed.ac.uk/jeh/Bio-PEPA/biopepa.html" + namespace VCell | "Virtual Cell" < Tool ; location &= "https://github.com/virtualcell/vcell" & "https://vcell.org/" & "https://en.wikipedia.org/wiki/Virtual_Cell" + namespace CellDesigner < Tool ; location &= "https://celldesigner.org/" + namespace ECell | "E-Cell" < Tool ; location &= "https://github.com/ecell/ecell4" & "https://www.e-cell.org/" + namespace RuleBender < Tool ; location &= "https://github.com/RuleWorld/rulebender" + + // --- New entries: Simulation Tools --- + namespace AnyLogic < Tool ; location &= "https://www.anylogic.com/" & "https://en.wikipedia.org/wiki/AnyLogic" + namespace Arena | "Arena Simulation" < Tool ; location &= "https://www.rockwellautomation.com/en-us/products/software/arena-simulation.html" & "https://en.wikipedia.org/wiki/Arena_(software)" + namespace PtolemyII | "Ptolemy II" < Tool ; location &= "https://github.com/icyphy/ptII" & "https://ptolemy.berkeley.edu/ptolemyII/" & "https://en.wikipedia.org/wiki/Ptolemy_Project" + namespace ns3 | "ns-3" < Tool ; location &= "https://gitlab.com/nsnam/ns-3-dev" & "https://www.nsnam.org/" + namespace NESTML < Language(".nestml") ; location &= "https://github.com/nest/nestml" + namespace GENESIS | "GENESIS Simulator" < Tool ; location &= "https://github.com/genesis-sim/genesis-2.4" & "http://www.genesis-sim.org/GENESIS/" & "https://en.wikipedia.org/wiki/GENESIS_(software)" + + // --- New entries: Probabilistic Programming (additional) --- + namespace OmegaJl | "Omega.jl" < Language(".jl") ; location &= "https://github.com/zenna/Omega.jl" + + // --- New entries: Computational Neuroscience Markup --- + namespace NineML < Language(".xml") ; location &= "https://github.com/INCF/nineml-spec" & "http://nineml.net/" + + // --- New entries: Constraint Programming (additional) --- + namespace CHIP | "Constraint Handling in Prolog" < Language(".clp") ; location &= "https://en.wikipedia.org/wiki/CHIP_(programming_language)" + + // --- New entries: Knowledge Graph Tools --- + namespace Neo4j < Tool ; location &= "https://github.com/neo4j/neo4j" & "https://neo4j.com/" & "https://en.wikipedia.org/wiki/Neo4j" + namespace Wikidata < Tool ; location &= "https://github.com/Wikidata" & "https://www.wikidata.org/" & "https://en.wikipedia.org/wiki/Wikidata" + namespace Freebase < Tool ; location &= "https://github.com/nchah/freebase-mql" & "https://en.wikipedia.org/wiki/Freebase_(database)" + namespace MQL | "Metaweb Query Language" < Language(".mql") + + // --- New entries: Languages from GitHub "programming-language" topic (by stars) --- + + // General-purpose / Systems languages + namespace Wenyan | "文言" < Language(".wy") ; location &= "https://github.com/wenyan-lang/wenyan" & "https://wy-lang.org/" + namespace XGo | "Go+" < Language(".gop") ; location &= "https://github.com/goplus/xgo" & "https://goplus.org/" + namespace Jank < Language(".jank") ; location &= "https://github.com/jank-lang/jank" & "https://jank-lang.org/" + namespace Jakt < Language(".jakt") ; location &= "https://github.com/SerenityOS/jakt" + namespace Erg < Language(".er") ; location &= "https://github.com/erg-lang/erg" & "https://erg-lang.org/" + namespace Beef < Language(".bf") ; location &= "https://github.com/beefytech/Beef" & "https://www.beeflang.org/" + namespace Nature < Language(".n") ; location &= "https://github.com/nature-lang/nature" & "https://nature-lang.org/" + namespace Umka < Language(".um") ; location &= "https://github.com/vtereshkov/umka-lang" + namespace Fusion | "Fut" < Language(".fut") ; location &= "https://github.com/fusionlanguage/fut" & "https://fusion-lang.org/" + namespace Wa | "凹语言" < Language(".wa") ; location &= "https://github.com/wa-lang/wa" & "https://wa-lang.org/" + namespace Peregrine < Language(".pe") ; location &= "https://github.com/SaptakBhoumik/Peregrine" + namespace C2 < Language(".c2") ; location &= "https://github.com/c2lang/c2compiler" & "http://c2lang.org/" + namespace Muon < Language(".muon") ; location &= "https://github.com/nickmqb/muon" + namespace Cone < Language(".cone") ; location &= "https://github.com/jondgoodwin/cone" & "http://cone.jondgoodwin.com/" + namespace Jule < Language(".jule") ; location &= "https://github.com/julelang/jule" & "https://jule.dev/" + namespace Alan < Language(".alan") ; location &= "https://github.com/alantech/alan" & "https://alan-lang.org/" + namespace Concrete < Language(".con") ; location &= "https://github.com/lambdaclass/concrete" + namespace Helix < Language(".hlx") ; location &= "https://github.com/kairolang/helix-lang" & "https://helix-lang.com/" + namespace Acton < Language(".act") ; location &= "https://github.com/actonlang/acton" & "https://www.acton-lang.org/" + namespace Savi < Language(".savi") ; location &= "https://github.com/savi-lang/savi" + namespace Alumina < Language(".alu") ; location &= "https://github.com/alumina-lang/alumina" & "https://docs.alumina-lang.net/" + namespace Compis < Language ; location &= "https://github.com/rsms/compis" + + // Embeddable / Scripting languages + namespace AviatorScript < Language(".av") ; location &= "https://github.com/killme2008/aviatorscript" + namespace Tengo < Language(".tengo") ; location &= "https://github.com/d5/tengo" + namespace Anko < Language(".ank") ; location &= "https://github.com/mattn/anko" + namespace PocketLang < Language(".pk") ; location &= "https://github.com/ThakeeNathees/pocketlang" + namespace Koto < Language(".koto") ; location &= "https://github.com/koto-lang/koto" & "https://koto.dev/" + namespace Rune < Language(".rn") ; location &= "https://github.com/rune-rs/rune" & "https://rune-rs.github.io/" + namespace Steel < Language(".scm") ; location &= "https://github.com/mattwparas/steel" + namespace Passerine < Language(".pn") ; location &= "https://github.com/vrtbl/passerine" + namespace Agora < Language(".agora") ; location &= "https://github.com/mna/agora" + namespace MiniScript < Language(".ms") ; location &= "https://github.com/JoeStrout/miniscript" & "https://miniscript.org/" + namespace ELENA < Language(".l") ; location &= "https://github.com/ELENA-LANG/elena-lang" + namespace Kinx < Language(".kx") ; location &= "https://github.com/Kray-G/kinx" + + // Functional / Type-theory languages + namespace Coconut < Language(".coco") ; location &= "https://github.com/evhub/coconut" & "https://coconut-lang.org/" + namespace Tao < Language(".tao") ; location &= "https://github.com/zesterer/tao" + namespace Hamler < Language(".hm") ; location &= "https://github.com/hamler-lang/hamler" & "https://www.hamler-lang.org/" + namespace Pikelet < Language(".pi") ; location &= "https://github.com/pikelet-lang/pikelet" + namespace Candy < Language(".candy") ; location &= "https://github.com/candy-lang/candy" + namespace Pen < Language(".pen") ; location &= "https://github.com/pen-lang/pen" & "https://pen-lang.org/" + namespace Fika < Language(".fika") ; location &= "https://github.com/fika-lang/fika" + namespace NeoHaskell < Language(".nehs") ; location &= "https://github.com/neohaskell/NeoHaskell" & "https://neohaskell.org/" + namespace Peridot < Language(".pdt") ; location &= "https://github.com/ehatti/peridot" + namespace Lawvere < Language(".law") ; location &= "https://github.com/jameshaydon/lawvere" + + // Typed / Verified languages + namespace CheckedC | "Checked C" < Language(".c") ; location &= "https://github.com/checkedc/checkedc" + namespace ISPC | "Intel SPMD Program Compiler" < Language(".ispc") ; location &= "https://github.com/ispc/ispc" & "https://ispc.github.io/" & "https://en.wikipedia.org/wiki/ISPC" + namespace CakeML < Language(".cml") ; location &= "https://github.com/CakeML/cakeml" & "https://cakeml.org/" + namespace EOLANG | "EO" < Language(".eo") ; location &= "https://github.com/objectionary/eo" & "https://www.eolang.org/" + + // Domain-specific languages + namespace Wuffs | "Wrangling Untrusted File Formats Safely" < Language(".wuffs") ; location &= "https://github.com/google/wuffs" + namespace SATySFi < Language(".saty") ; location &= "https://github.com/gfngfn/SATySFi" + namespace daScript | "daslang" < Language(".das") ; location &= "https://github.com/GaijinEntertainment/daScript" & "https://dascript.org/" + namespace Cmajor < Language(".cmajor") ; location &= "https://github.com/cmajor-lang/cmajor" & "https://cmajor.dev/" + namespace Gwion < Language(".gw") ; location &= "https://github.com/Gwion/Gwion" & "https://gwion.github.io/Gwion/" + namespace Seq < Language(".seq") ; location &= "https://github.com/seq-lang/seq" & "https://seq-lang.org/" + namespace Smudge < Language(".smudge") ; location &= "https://github.com/smudgelang/smudge" + namespace Fathom < Language(".fathom") ; location &= "https://github.com/yeslogic/fathom" + namespace Tokay < Language(".tok") ; location &= "https://github.com/tokay-lang/tokay" & "https://tokay.dev/" + namespace Cadence < Language(".cdc") ; location &= "https://github.com/onflow/cadence" & "https://cadence-lang.org/" + namespace Lurk < Language(".lurk") ; location &= "https://github.com/lurk-lab/lurk-beta" & "https://lurk-lang.org/" + namespace CSML | "Chatbot Script Markup Language" < Language(".csml") ; location &= "https://github.com/CSML-by-Clevy/csml-engine" & "https://www.csml.dev/" + namespace Bril | "Big Red Intermediate Language" < Language(".bril") ; location &= "https://github.com/sampsyo/bril" + namespace PatternLanguage | "ImHex Pattern Language" < Language(".hexpat") ; location &= "https://github.com/WerWolv/PatternLanguage" + namespace Numscript < Language(".num") ; location &= "https://github.com/formancehq/numscript" + + // Shell / CLI scripting languages + namespace NGS | "Next Generation Shell" < Language(".ngs") ; location &= "https://github.com/ngs-lang/ngs" & "https://ngs-lang.org/" + namespace ABS | "ABS Language" < Language(".abs") ; location &= "https://github.com/abs-lang/abs" & "https://www.abs-lang.org/" + namespace Cotowali < Language(".coto") ; location &= "https://github.com/cotowali/cotowali" + namespace Rad < Language(".rad") ; location &= "https://github.com/amterp/rad" + + // Lua variants / extensions + namespace Ravi < Language(".lua") ; location &= "https://github.com/dibyendumajumdar/ravi" + namespace Pluto | "PlutoLang" < Language(".pluto") ; location &= "https://github.com/PlutoLang/Pluto" & "https://pluto-lang.org/" + namespace Kuroko < Language(".krk") ; location &= "https://github.com/kuroko-lang/kuroko" & "https://kuroko-lang.github.io/" + namespace Clue < Language(".clue") ; location &= "https://github.com/ClueLang/Clue" + + // Language variants on other VMs + namespace Clojerl | "Clojure for Erlang VM" < Language(".clje") ; location &= "https://github.com/clojerl/clojerl" + namespace Phel < Language(".phel") ; location &= "https://github.com/phel-lang/phel-lang" & "https://phel-lang.org/" + namespace Golo < Language(".golo") ; location &= "https://github.com/eclipse-archived/golo-lang" + namespace Sesterl < Language(".sest") ; location &= "https://github.com/gfngfn/Sesterl" + + // Visual / Dataflow programming + namespace Snap | "Snap!" < Tool ; location &= "https://github.com/jmoenig/Snap" & "https://snap.berkeley.edu/" & "https://en.wikipedia.org/wiki/Snap!_(programming_language)" + namespace Neva < Language(".neva") ; location &= "https://github.com/nevalang/neva" & "https://nevalang.org/" + namespace Lamdu < Tool ; location &= "https://github.com/lamdu/lamdu" & "http://www.lamdu.org/" + + // Service-oriented / Web languages + namespace Eve < Language(".eve") ; location &= "https://github.com/witheve/Eve" + namespace Imba < Language(".imba") ; location &= "https://github.com/imba/imba" & "https://imba.io/" + namespace Penrose < Language(".substance" | ".style" | ".domain") ; location &= "https://github.com/penrose/penrose" & "https://penrose.cs.cmu.edu/" + namespace Jolie < Language(".ol") ; location &= "https://github.com/jolie/jolie" & "https://www.jolie-lang.org/" & "https://en.wikipedia.org/wiki/Jolie_(programming_language)" + namespace Coi < Language(".coi") ; location &= "https://github.com/io-eric/coi" + namespace Grace < Language(".grace") ; location &= "https://github.com/Gabriella439/grace" + + // Mathematical / Scientific + namespace Egison < Language(".egi") ; location &= "https://github.com/egison/egison" & "https://www.egison.org/" + namespace Wax < Language(".wax") ; location &= "https://github.com/LingDong-/wax" + namespace DDlog | "Differential Datalog" < Language(".dl") ; location &= "https://github.com/vmware-archive/differential-datalog" + + // Esoteric / Cultural languages + namespace Cantonese | "粤语" < Language(".cts") ; location &= "https://github.com/StepfenShawn/Cantonese" + namespace AsciiDots < Language(".dots") ; location &= "https://github.com/aaronjanse/asciidots" + namespace HolyC < Language(".hc") ; location &= "https://github.com/Jamesbarford/holyc-lang" + namespace Fetlang < Language(".fet") ; location &= "https://github.com/fetlang/fetlang" + namespace Kip < Language(".kip") ; location &= "https://github.com/kip-dili/kip" + namespace Latino < Language(".lat") ; location &= "https://github.com/lenguaje-latino/latino" + namespace Nadesiko | "なでしこ" < Language(".nako3") ; location &= "https://github.com/kujirahand/nadesiko3" & "https://nadesi.com/" + namespace Vedic < Language(".ved") ; location &= "https://github.com/vedic-lang/vedic" + namespace Vyxal < Language(".vy") ; location &= "https://github.com/Vyxal/Vyxal" + namespace Nuri | "누리" < Language(".nuri") ; location &= "https://github.com/suhdonghwi/nuri" + + // Music / Audio programming + namespace Clio < Language(".clio") ; location &= "https://github.com/clio-lang/clio" & "https://clio-lang.org/" + namespace ArkScript < Language(".ark") ; location &= "https://github.com/ArkScript-lang/Ark" & "https://arkscript-lang.dev/" + namespace Rye < Language(".rye") ; location &= "https://github.com/refaktor/rye" & "https://ryelang.org/" + + // Embeddable / Game scripting + namespace Sui < Language(".sui") ; location &= "https://github.com/TakatoHonda/sui-lang" + namespace Blisp < Language(".blisp") ; location &= "https://github.com/ytakano/blisp" + + // Low-level / Retro computing + namespace Millfork < Language(".mfk") ; location &= "https://github.com/KarolS/millfork" + namespace Vox < Language(".vx") ; location &= "https://github.com/MrSmith33/vox" + namespace EndBASIC < Language(".bas") ; location &= "https://github.com/endbasic/endbasic" & "https://endbasic.dev/" + namespace Prog8 < Language(".p8") ; location &= "https://github.com/irmen/prog8" & "https://prog8.readthedocs.io/" + namespace NimSkull < Language(".nim") ; location &= "https://github.com/nim-works/nimskull" + + // Other notable languages + namespace Ink | "Ink (thesephist)" < Language(".ink") ; location &= "https://github.com/thesephist/ink" + namespace Oak < Language(".oak") ; location &= "https://github.com/thesephist/oak" & "https://oaklang.org/" + namespace Lone < Language(".lone") ; location &= "https://github.com/lone-lang/lone" + namespace Chaos < Language(".kaos") ; location &= "https://github.com/chaos-lang/chaos" & "https://chaos-lang.org/" + namespace XL < Language(".xl") ; location &= "https://github.com/c3d/xl" & "https://xlr.sourceforge.io/" + namespace Dictu < Language(".du") ; location &= "https://github.com/dictu-lang/Dictu" & "https://dictu-lang.com/" + namespace Mond < Language(".mnd") ; location &= "https://github.com/Rohansi/Mond" + namespace Newspeak < Language(".ns") ; location &= "https://github.com/newspeaklanguage/newspeak" & "https://newspeaklanguage.org/" & "https://en.wikipedia.org/wiki/Newspeak_(programming_language)" + namespace Aqua < Language(".aqua") ; location &= "https://github.com/fluencelabs/aqua" & "https://fluence.dev/" + namespace CashScript < Language(".cash") ; location &= "https://github.com/CashScript/cashscript" & "https://cashscript.org/" + namespace GDL | "GNU Data Language" < Language(".pro") ; location &= "https://github.com/gnudatalanguage/gdl" & "https://gnudatalanguage.github.io/" + namespace Nelson < Language(".m") ; location &= "https://github.com/nelson-lang/nelson" & "https://nelson-numerical-software.github.io/nelson-website/" + namespace Catspeak < Language(".meow") ; location &= "https://github.com/katsaii/catspeak-lang" + namespace Sidef < Language(".sf") ; location &= "https://github.com/trizen/sidef" + namespace Citrine < Language(".ctr") ; location &= "https://github.com/gabordemooij/citrine" & "https://citrine-lang.org/" + namespace Panda < Language(".panda") ; location &= "https://github.com/panda-lang/panda" + namespace Jason | "AgentSpeak" < Language(".asl") ; location &= "https://github.com/jason-lang/jason" & "https://jason-lang.github.io/" & "https://en.wikipedia.org/wiki/AgentSpeak" + namespace SARL < Language(".sarl") ; location &= "https://github.com/sarl/sarl" & "http://www.sarl.io/" & "https://en.wikipedia.org/wiki/SARL_language" + namespace Fuzion < Language(".fz") ; location &= "https://github.com/tokiwa-software/fuzion" & "https://fuzion-lang.dev/" + namespace Mimium < Language(".mmm") ; location &= "https://github.com/mimium-org/mimium-rs" & "https://mimium.org/" + namespace Blade < Language(".b") ; location &= "https://github.com/blade-lang/blade" & "https://bladelang.com/" + namespace Forscape < Language(".π") ; location &= "https://github.com/JohnDTill/Forscape" + + // --- New entries: Additional languages from GitHub "programming-language" topic --- + + // General-purpose / Systems + namespace OneLang < Language(".one") ; location &= "https://github.com/onelang/OneLang" + namespace Rue < Language(".rue") ; location &= "https://github.com/rue-language/rue" + namespace Neugram < Language(".ng") ; location &= "https://github.com/neugram/ng" + namespace Koral < Language(".kor") ; location &= "https://github.com/kulics/koral" + namespace eC < Language(".ec") ; location &= "https://github.com/ecere/ecere-sdk" & "http://ec-lang.org/" + namespace NULLC < Language(".nc") ; location &= "https://github.com/WheretIB/nullc" + namespace Objeck < Language(".obs") ; location &= "https://github.com/objeck/objeck-lang" + namespace Flax < Language(".flx") ; location &= "https://github.com/flax-lang/flax" + namespace Feral < Language(".fer") ; location &= "https://github.com/Feral-Lang/Feral" + namespace CovScript < Language(".csc") ; location &= "https://github.com/covscript/covscript" + namespace Yona < Language(".yona") ; location &= "https://github.com/yona-lang/yona" + namespace Qore < Language(".q") ; location &= "https://github.com/qoretechnologies/qore" & "https://qore.org/" + namespace Yaksha < Language(".yaka") ; location &= "https://github.com/YakshaLang/Yaksha" + namespace Temper < Language(".temper") ; location &= "https://github.com/temperlang/temper" + namespace Lumina < Language(".lm") ; location &= "https://github.com/luminalang/lumina" + + // Embeddable / Scripting + namespace Melang < Language(".m") ; location &= "https://github.com/Water-Melon/Melang" + namespace Never < Language(".nev") ; location &= "https://github.com/never-lang/never" + namespace Myst < Language(".mt") ; location &= "https://github.com/myst-lang/myst" + namespace TopShell < Language(".tsh") ; location &= "https://github.com/topshell-language/topshell" + namespace Wu < Language(".wu") ; location &= "https://github.com/wu-lang/wu" + namespace Gentee < Language(".g") ; location &= "https://github.com/gentee/gentee" + namespace MY_BASIC | "MY-BASIC" < Language(".bas") ; location &= "https://github.com/paladin-t/my_basic" + + // Functional / Type-theory + namespace Morloc < Language(".loc") ; location &= "https://github.com/morloc-project/morloc" + namespace Finkel < Language(".fnk") ; location &= "https://github.com/finkel-lang/finkel" + namespace Mlatu < Language(".mlatu") ; location &= "https://github.com/mlatu-lang/mlatu" + namespace GoCaml < Language(".ml") ; location &= "https://github.com/rhysd/gocaml" + namespace Cicada < Language(".cic") ; location &= "https://github.com/cicada-lang/cicada-solo" + namespace Bruijn < Language(".bruijn") ; location &= "https://github.com/marvinborner/bruijn" + namespace Niva < Language(".niva") ; location &= "https://github.com/gavr123456789/Niva" + + // Domain-specific + namespace Slang | "Slang Audio" < Language(".slang") ; location &= "https://github.com/kylestetz/slang" + namespace AskQL < Language(".ask") ; location &= "https://github.com/CatchTheTornado/askql" + namespace Tensorlang < Language(".tl") ; location &= "https://github.com/tensorlang/tensorlang" + namespace NPL | "Neural Parallel Language" < Language(".npl") ; location &= "https://github.com/LiXizhi/NPLRuntime" + namespace Rant < Language(".rant") ; location &= "https://github.com/rant-lang/rant" + namespace Empirical < Language(".emp") ; location &= "https://github.com/empirical-soft/empirical-lang" + namespace ThingTalk < Language(".tt") ; location &= "https://github.com/stanford-oval/thingtalk" + namespace Mech < Language(".mec") ; location &= "https://github.com/mech-lang/mech" + + // Blockchain / Smart contracts + namespace Helios < Language(".hl") ; location &= "https://github.com/HeliosLang/compiler" + namespace OpShin < Language(".py") ; location &= "https://github.com/OpShin/opshin" + namespace Zkay < Language(".zkay") ; location &= "https://github.com/eth-sri/zkay" + + // Verification / Formal + namespace Silver | "Viper IL" < Language(".sil") ; location &= "https://github.com/viperproject/silver" + namespace SUS | "SUS HDL" < Language(".sus") ; location &= "https://github.com/pc2/sus-compiler" + namespace OberonC | "Oberon-07" < Language(".ob") ; location &= "https://github.com/lboasso/oberonc" + + // Concurrent / Distributed + namespace Orc < Language(".orc") ; location &= "https://github.com/orc-lang/orc" & "https://orc-csres.github.io/orc/" & "https://en.wikipedia.org/wiki/Orc_(programming_language)" + namespace Slate < Language(".slate") ; location &= "https://github.com/briantrice/slate-language" + + // Scheme / Lisp variants + namespace OtusLisp | "Ol" < Language(".ol") ; location &= "https://github.com/yuriy-chumak/ol" + namespace dg < Language(".dg") ; location &= "https://github.com/pyos/dg" + namespace OK | "K5 Interpreter" < Language(".k") ; location &= "https://github.com/JohnEarnest/ok" + + // Retro / Low-level + namespace PLASMA < Language(".pla") ; location &= "https://github.com/dschmenk/PLASMA" + namespace LDPL < Language(".ldpl") ; location &= "https://github.com/Lartu/ldpl" + namespace 3BC < Language(".3bc") ; location &= "https://github.com/RodrigoDornelles/3bc-lang" + + // Game / Visual + namespace ZSharp | "Z#" < Language(".zs") ; location &= "https://github.com/sam-astro/Z-Sharp" + namespace Cerberus < Language(".cxs") ; location &= "https://github.com/PhilMoe/cerberus" + namespace Grapycal < Tool ; location &= "https://github.com/Grapycal/Grapycal" + namespace Fanx < Language(".fan") ; location &= "https://github.com/fanx-dev/fanx" + + // Esoteric / Cultural + namespace BhaiLang < Language(".bhai") ; location &= "https://github.com/DulLabs/bhai-lang" + namespace Folders < Language ; location &= "https://github.com/rottytooth/Folders" + namespace Retina < Language(".ret") ; location &= "https://github.com/m-ender/retina" + namespace Tampio < Language(".tampio") ; location &= "https://github.com/fergusq/tampio" + namespace DDP | "Deutsche Programmiersprache" < Language(".ddp") ; location &= "https://github.com/DDP-Projekt/Kompilierer" + namespace EasyLang < Language(".easy") ; location &= "https://github.com/chkas/easylang" & "https://easylang.dev/" + + // Non-English natural language PLs + namespace Egua < Language(".egua") ; location &= "https://github.com/eguadev/egua" + namespace Potigol < Language(".poti") ; location &= "https://github.com/potigol/potigol" + namespace Ezhil | "எழில்" < Language(".n") ; location &= "https://github.com/Ezhil-Language-Foundation/Ezhil-Lang" + namespace Naskah < Language(".nsk") ; location &= "https://github.com/pveyes/naskah" + namespace Kin < Language(".kin") ; location &= "https://github.com/kin-lang/kin" + namespace Tu | "凸" < Language(".tu") ; location &= "https://github.com/tu-lang/tu" + namespace Linotte < Language(".liv") ; location &= "https://github.com/cpc6128/LangageLinotte" + namespace EsJS < Language(".esjs") ; location &= "https://github.com/es-js/esjs" + namespace Wollok < Language(".wlk") ; location &= "https://github.com/uqbar-project/wollok" + + // --- GitHub topic:programming-language (10-32 stars) --- + // General-purpose / Compiled + namespace Thrush < Language ; location &= "https://github.com/thrushlang/thrushc" + namespace Azula < Language ; location &= "https://github.com/azula-lang/azula" + namespace Sand < Language ; location &= "https://github.com/sand-lang/sand" + namespace ASPL < Language ; location &= "https://github.com/aspl-lang/aspl" + namespace Enact < Language ; location &= "https://github.com/enact-lang/enact" + namespace Fastcode < Language ; location &= "https://github.com/TheRealMichaelWang/fastcode" + namespace Chemical < Language ; location &= "https://github.com/chemicallang/chemical" + namespace Colgm < Language ; location &= "https://github.com/colgm/colgm" + namespace Sunder < Language ; location &= "https://github.com/ashn-dot-dev/sunder" + namespace Bluebird < Language ; location &= "https://github.com/csb6/bluebird" + namespace Gera < Language ; location &= "https://github.com/geralang/geralc" + namespace OrbLang | "Orb" < Language ; location &= "https://github.com/vplesko/OrbLang" + namespace Rho < Language ; location &= "https://github.com/arshajii/rho" + namespace Ullage < Language ; location &= "https://github.com/iwillspeak/ullage" + namespace HashLang | "Hash" < Language ; location &= "https://github.com/hash-org/hashc" + namespace NOMA < Language ; location &= "https://github.com/pierridotite/NOMA" + namespace Brisk < Language ; location &= "https://github.com/spotandjake/Brisk" + namespace NOS < Language ; location &= "https://github.com/LUK3D/NOS" + namespace Jou < Language ; location &= "https://github.com/Akuli/jou" + namespace Void < Language ; location &= "https://github.com/VoidLang/void" + namespace Aeon < Language ; location &= "https://github.com/alcides/aeon" + namespace Sapphire < Language ; location &= "https://github.com/foxzyt/Sapphire" + namespace Bone < Language ; location &= "https://github.com/desktopgame/bone" + namespace Relax < Language ; location &= "https://github.com/CloakerSmoker/Relax-Language" + namespace BreadCrumbs | "bread-crumbs" < Language ; location &= "https://github.com/Bre4dGC/bread-crumbs" + namespace Okta < Language ; location &= "https://github.com/mikelma/oktac" + namespace Stove < Language ; location &= "https://github.com/asxez/stove" + namespace Scribe < Language ; location &= "https://github.com/scribe-lang/scribe" + namespace VSharp | "V#" < Language ; location &= "https://github.com/funcieqDEV/VSharp" + namespace CheezLang | "Cheez" < Language ; location &= "https://github.com/CheezLang/CheezLang" + namespace Dust < Language ; location &= "https://github.com/DustLanguage/Dust" + namespace Wright < Language ; location &= "https://github.com/vcfxb/wright-lang" + namespace Hap < Language ; location &= "https://github.com/evincarofautumn/Hap" + + // Scripting / Interpreted + namespace Samarium < Language ; location &= "https://github.com/samarium-lang/Samarium" + namespace Minilang < Language ; location &= "https://github.com/wrapl/minilang" + namespace PointerScript < Language ; location &= "https://github.com/M4GNV5/PointerScript" + namespace Aphid < Language ; location &= "https://github.com/John-Leitch/Aphid" + namespace Kavascript < Language ; location &= "https://github.com/maximecb/kavascript" + namespace MinScriptLang < Language ; location &= "https://github.com/sawickiap/MinScriptLang" + namespace Tsuki < Language ; location &= "https://github.com/tsuki-lang/tsuki" + namespace Cosy < Language ; location &= "https://github.com/anissen/cosy" + namespace Mussel < Language ; location &= "https://github.com/gianndev/mussel" + namespace Piccolo < Language ; location &= "https://github.com/PiccoloLang/piccolo" + namespace Nyx < Language ; location &= "https://github.com/y1yang0/nyx" + namespace Eevo < Language ; location &= "https://github.com/eevolang/eevo" + namespace Modu < Language ; location &= "https://github.com/cyteon/modu" + namespace Truck < Language ; location &= "https://github.com/tarptaeya/Truck" + namespace Mani < Language ; location &= "https://github.com/mani-language/Mani" + namespace Radon < Language ; location &= "https://github.com/radon-project/radon" + namespace Tank < Language ; location &= "https://github.com/AmrDeveloper/Tank" + namespace Tern < Language ; location &= "https://github.com/tern-lang/tern" + namespace Zuko < Language ; location &= "https://github.com/shehryar49/zuko" + namespace Ham < Language ; location &= "https://github.com/marc2332/ham" + namespace Grotsky < Language ; location &= "https://github.com/mliezun/grotsky" + namespace Quetite < Language ; location &= "https://github.com/qewer33/quetite" + namespace Luxya < Language ; location &= "https://github.com/franeklubi/luxya" + namespace Riff < Language ; location &= "https://github.com/riff-lang/riff" + namespace BerryMath < Language ; location &= "https://github.com/BerryMathDevelopmentTeam/BerryMath" + namespace Kesh < Language ; location &= "https://github.com/kesh-lang/kesh" + namespace Dern < Language ; location &= "https://github.com/octaspire/dern" + namespace Meevax < Language ; location &= "https://github.com/yamacir-kit/meevax" + namespace Rocklang < Language ; location &= "https://github.com/jarkonik/rocklang" + namespace Jasl < Language ; location &= "https://github.com/benhj/jasl" + namespace Arrow < Language ; location &= "https://github.com/benhj/arrow" + namespace Opal < Language ; location &= "https://github.com/iitalics/Opal" + namespace Zrc < Language ; location &= "https://github.com/Edd12321/zrc" + namespace Ethereal < Language ; location &= "https://github.com/Synthesized-Infinity/Ethereal" + namespace Square < Language ; location &= "https://github.com/square-lang/Square" + + // Functional / Typed + namespace Paso < Language ; location &= "https://github.com/SimonHauguel/Paso" + namespace Bramble < Language ; location &= "https://github.com/chameco/bramble" + namespace Madlib < Language ; location &= "https://github.com/madlib-lang/madlib" + namespace Schmu < Language ; location &= "https://github.com/tjammer/schmu" + namespace Koneko < Language ; location &= "https://github.com/obfusk/koneko" + namespace Bella < Language ; location &= "https://github.com/MystPi/bella" + namespace Jet < Language ; location &= "https://github.com/i2y/jet" + namespace FunL < Language ; location &= "https://github.com/anssihalmeaho/funl" + namespace Pangaea < Language ; location &= "https://github.com/Syuparn/Pangaea" + namespace SakiLang | "Saki" < Language ; location &= "https://github.com/saki-lang/saki-dev" + namespace MLPolyR < Language ; location &= "https://github.com/owo-lang/MLPolyR" + namespace Hasp < Language ; location &= "https://github.com/aliclark/hasp" + namespace Cassidy < Language ; location &= "https://github.com/cassidylang/cassidy" + namespace VSL < Language ; location &= "https://github.com/vsl-lang/VSL" + namespace Csq | "C²" < Language ; location &= "https://github.com/CsqLang/Csq" + namespace IonFusion | "Ion Fusion" < Language ; location &= "https://github.com/ion-fusion/fusion-java" + namespace Dosato < Language ; location &= "https://github.com/Robotnik08/cdosato" + + // Lisp / Forth variants + namespace Raillisp < Language ; location &= "https://github.com/mschuldt/raillisp" + namespace Lel < Language ; location &= "https://github.com/Lel-Language/Lisp-esque-language" + namespace Nujel < Language ; location &= "https://github.com/Melchizedek6809/Nujel" + namespace Element0 | "element-0" < Language ; location &= "https://github.com/Element0Lang/element-0" + namespace Murmel < Language ; location &= "https://github.com/mayerrobert/jmurmel" + namespace KForth64 | "kForth-64" < Language(".4th") ; location &= "https://github.com/mynenik/kForth-64" + namespace Equinox < Language ; location &= "https://github.com/zeroflag/equinox" + namespace FCL | "Forth Calculator's Language" < Language ; location &= "https://github.com/zeroflag/fcl" + namespace Glas < Language ; location &= "https://github.com/dmbarbour/glas" + + // Stack-based + namespace Ram < Language ; location &= "https://github.com/ujjwal-kr/ram" + namespace Stck < Language ; location &= "https://github.com/teodoran/stck" + namespace Haystack < Language ; location &= "https://github.com/rtulip/haystack" + namespace Tovie < Language ; location &= "https://github.com/Jaysmito101/tovie" + + // Shell / CLI + namespace Riptide < Language ; location &= "https://github.com/sagebind/riptide" + namespace EZ < Language ; location &= "https://github.com/SchoolyB/EZ" + + // Domain-specific + namespace JAMScript < Language ; location &= "https://github.com/citelab/JAMScript" + namespace AcaciaMC | "AcaciaMC" < Language ; location &= "https://github.com/CBerJun/AcaciaMC" + namespace MCCompiled < Language ; location &= "https://github.com/7UKECREAT0R/MCCompiled" + namespace CsvPlusPlus | "csv++" < Language ; location &= "https://github.com/patrickomatic/csv-plus-plus" + namespace WHEN < Language ; location &= "https://github.com/PhialsBasement/WHEN-Language" + namespace Doolang | "Doo" < Language ; location &= "https://github.com/nynrathod/doolang" + namespace Imperator < Language ; location &= "https://github.com/OpShin/imperator" + namespace Nubo < Language ; location &= "https://github.com/nubolang/nubo" + namespace Wala < Language ; location &= "https://github.com/CalmSystem/wala" + namespace RESOLVE < Language ; location &= "https://github.com/ClemsonRSRG/RESOLVE" + namespace Gloa | "Glóa" < Language ; location &= "https://github.com/ReFreezed/Gloa" + namespace Scar < Language ; location &= "https://github.com/scar-lang/scar" + + // Embeddable / Tiny + namespace TinySelf < Language ; location &= "https://github.com/Bystroushaak/tinySelf" + namespace BirbLang | "Birb" < Language ; location &= "https://github.com/Calamity210/BirbLang" + namespace Steak < Language ; location &= "https://github.com/overlogged/steak" + namespace Lazy < Language ; location &= "https://github.com/lazy-lang/Lazy" + namespace GolfCart < Language ; location &= "https://github.com/healeycodes/golfcart" + namespace Up < Language ; location &= "https://github.com/KennethanCeyer/up" + namespace NLang | "N-lang" < Language ; location &= "https://github.com/nbuilding/N-lang" + + // Esoteric + namespace Lolz < Language ; location &= "https://github.com/cevatbarisyilmaz/lolz" + namespace Cubically < Language ; location &= "https://github.com/aaronryank/Cubically" + namespace FlufflePuff < Language ; location &= "https://github.com/juju2143/flufflepuff" + namespace StackCats < Language ; location &= "https://github.com/m-ender/stackcats" + namespace Trilangle < Language ; location &= "https://github.com/bbrk24/Trilangle" + namespace Barrel < Language ; location &= "https://github.com/joes-esolangs/barrel" + namespace Naz < Language ; location &= "https://github.com/sporeball/naz" + namespace Mascarpone < Language ; location &= "https://github.com/catseye/Mascarpone" + namespace Moon < Language ; location &= "https://github.com/GanerCodes/moon" + namespace Adventlang < Language ; location &= "https://github.com/healeycodes/adventlang" + namespace FFlat | "F♭" < Language ; location &= "https://github.com/Hypercubed/f-flat_node" + + // Non-English syntax (additional) + namespace Salam < Language ; location &= "https://github.com/SalamLang/Salam" + namespace Agaram < Language ; location &= "https://github.com/naveen17797/Agaram" + namespace Ettayi < Language ; location &= "https://github.com/Apollo-Blaze/ettayi" + namespace DariX < Language ; location &= "https://github.com/shayanheidari01/DariX" + namespace Ena < Language ; location &= "https://github.com/pgagnidze/ena" + namespace Saral | "Šaral" < Language ; location &= "https://github.com/PaulNoth/saral" + namespace SomonScript | "Somon Script" < Language ; location &= "https://github.com/lindentechde/Somon-Script" + namespace SpedeScript < Language ; location &= "https://github.com/janit/spedescript" + namespace Setonas < Language ; location &= "https://github.com/Setonas/setonas" + + // Experimental / Other + namespace TopoLang < Language ; location &= "https://github.com/tneukom/topolang" + namespace Hades < Language ; location &= "https://github.com/dhruvrajvanshi/hades-lang" + namespace Alox < Language ; location &= "https://github.com/alox-ai/alox-old" + namespace Drona < Language ; location &= "https://github.com/Drona-Org/Drona" + namespace Cafe < Language ; location &= "https://github.com/cafe-jvm-lang/cafe" + namespace Avalon < Language ; location &= "https://github.com/avalon-lang/avaloni" + namespace Dil < Language ; location &= "https://github.com/ACM-UoA-Student-Chapter/dil" + namespace CupScript < Language ; location &= "https://github.com/Fus3n/cupscript" + namespace PyHP | "PyHP++#" < Language ; location &= "https://github.com/PyHP-pph/PyHP_pph" + namespace Tay < Language ; location &= "https://github.com/mesuutt/tay" + namespace Tutara < Language ; location &= "https://github.com/tutara/tutara" + namespace Esta < Language ; location &= "https://github.com/epellis/esta" + namespace BCL < Language ; location &= "https://github.com/ArachnidAbby/BCL" + namespace Good < Language ; location &= "https://github.com/goodlang/good" + namespace PostfixHaskell | "postfix-haskell" < Language ; location &= "https://github.com/dvtate/postfix-haskell" + namespace Stamon < Language ; location &= "https://github.com/CLimber-Rong/stamon" + namespace Raven < Language ; location &= "https://github.com/martian56/raven" + namespace TurboriumBasic < Language ; location &= "https://github.com/turborium/TurboriumBasic" + namespace Paco < Language ; location &= "https://github.com/hugolgst/paco" + + // --- GitHub topic:programming-language (5-9 stars, curated) --- + // Unique concepts + namespace LambdaQ < Language ; location &= "https://github.com/radumarg/lambdaQ" + namespace Railway < Language ; location &= "https://github.com/jndean/Railway" + namespace Pearl < Language ; location &= "https://github.com/pearl-lang/pearl" + namespace LightDP < Language ; location &= "https://github.com/yuxincs/lightdp" + namespace PILOTS < Language ; location &= "https://github.com/RPI-WCL/pilots" + namespace Ekitai < Language ; location &= "https://github.com/tarberd/ekitai" + namespace Box < Language ; location &= "https://github.com/intsuc/box" + namespace SanskritVM | "Sanskrit" < Language ; location &= "https://github.com/tawaren/Sanskrit" + namespace Deck < Language ; location &= "https://github.com/Jackojc/deck" + namespace Styff < Language ; location &= "https://github.com/aradarbel10/Styff" + namespace MiniYu | "mini-yu" < Language ; location &= "https://github.com/andreaslyn/mini-yu" + namespace Stone < Language ; location &= "https://github.com/stone-lang/stone" + namespace Blossom < Language ; location &= "https://github.com/IMP1/blossom" + namespace GdMinus | "gdminus" < Language ; location &= "https://github.com/saltysystems/gdminus" + namespace SLOBIL < Language ; location &= "https://github.com/flynnzac/slobil" + namespace Tin < Language ; location &= "https://github.com/The-Tin-Foil-Hat-Society/tin" + namespace Horse64 < Language ; location &= "https://github.com/Horse64/core.horse64.org" + namespace Abra < Language ; location &= "https://github.com/anandrav/abra" + namespace Remix < Language ; location &= "https://github.com/rsheehan/Remix" + namespace Lichen < Language ; location &= "https://github.com/mikumikudice/lichen" + namespace Fyrlang | "Fyr" < Language ; location &= "https://github.com/vs-ude/fyrlang" + namespace Incan < Language ; location &= "https://github.com/dannys-code-corner/incan" + + // Non-English syntax (5-9 stars) + namespace SwaziLang < Language ; location &= "https://github.com/godieGH/SwaziLang" + namespace ArmaLang < Language ; location &= "https://github.com/ibrahimesseddyq/ArmaLang" + namespace VNC < Language ; location &= "https://github.com/nguyenphuminh/VNC" + namespace Coz < Language ; location &= "https://github.com/abdllhygt/coz" + namespace Tagalang < Language ; location &= "https://github.com/jabezborja/tagalang" + namespace Ounglang < Language ; location &= "https://github.com/pnxguide/ounglang" + namespace MolluLang | "몰?루" < Language ; location &= "https://github.com/bukgeuk-penguin/mollu-lang" + // Libraries Language namespace BabylonJS < Library ; location &= "https://github.com/BabylonJS" @@ -773,6 +1645,87 @@ Language namespace lambeq < Library ; location &= "https://github.com/CQCL/lambeq" & "https://docs.quantinuum.com/lambeq/" namespace nLab < Library ; location &= "https://ncatlab.org/" namespace XenaProject | Xena < Library ; location &= "https://github.com/kbuzzard/xena" & "https://xenaproject.wordpress.com/" & "https://www.ma.imperial.ac.uk/~buzzard/xena/" + // --- New: Formalized Mathematics Libraries --- + namespace Mathlib | "Mathlib4" < Library ; location &= "https://github.com/leanprover-community/mathlib4" + namespace MathComp | "Mathematical Components" < Library ; location &= "https://github.com/math-comp/math-comp" & "https://math-comp.github.io/" + namespace AFP | "Archive of Formal Proofs" < Library ; location &= "https://github.com/isabelle-prover/mirror-afp-devel" & "https://www.isa-afp.org/" + namespace CoqHoTT | "Coq-HoTT" < Library ; location &= "https://github.com/HoTT/Coq-HoTT" + namespace HoTTAgda | "HoTT-Agda" < Library ; location &= "https://github.com/HoTT/HoTT-Agda" + namespace AgdaCubical | "Agda Cubical Library" < Library ; location &= "https://github.com/agda/cubical" + namespace TypeTopology < Library ; location &= "https://github.com/martinescardo/TypeTopology" + namespace 1Lab < Library ; location &= "https://github.com/the1lab/1lab" & "https://1lab.dev/" + namespace CoqEAL | "Coq Effective Algebra Library" < Library ; location &= "https://github.com/rocq-community/coqeal" + // --- New: Category Theory Libraries --- + namespace CatlabJl | "Catlab.jl" < Library ; location &= "https://github.com/AlgebraicJulia/Catlab.jl" & "https://algebraicjulia.github.io/Catlab.jl/" + namespace idrisct | "idris-ct" < Library ; location &= "https://github.com/statebox/idris-ct" + // --- New: Number Theory / Algebra Libraries --- + namespace NemoJl | "Nemo.jl" < Library ; location &= "https://github.com/Nemocas/Nemo.jl" + namespace AbstractAlgebraJl | "AbstractAlgebra.jl" < Library ; location &= "https://github.com/Nemocas/AbstractAlgebra.jl" + namespace HeckeJl | "Hecke.jl" < Library ; location &= "https://github.com/thofma/Hecke.jl" + namespace OSCARJl | "OSCAR.jl" < Library ; location &= "https://github.com/oscar-system/Oscar.jl" & "https://www.oscar-system.org/" + namespace Normaliz < Library ; location &= "https://github.com/Normaliz/Normaliz" & "https://en.wikipedia.org/wiki/Normaliz" + // --- New: Term Rewriting Libraries --- + namespace egg | "e-graphs good" < Library ; location &= "https://github.com/egraphs-good/egg" + namespace MetatheoryJl | "Metatheory.jl" < Library ; location &= "https://github.com/JuliaSymbolics/Metatheory.jl" + // --- New: Category Theory Libraries --- + namespace AlgebraicRewritingJl | "AlgebraicRewriting.jl" < Library ; location &= "https://github.com/AlgebraicJulia/AlgebraicRewriting.jl" + namespace AlgebraicPetriJl | "AlgebraicPetri.jl" < Library ; location &= "https://github.com/AlgebraicJulia/AlgebraicPetri.jl" + namespace DecapodesJl | "Decapodes.jl" < Library ; location &= "https://github.com/AlgebraicJulia/Decapodes.jl" + namespace catgrad < Library ; location &= "https://github.com/statusfailed/catgrad" + namespace OpenHypergraphs | "open-hypergraphs" < Library ; location &= "https://github.com/statusfailed/open-hypergraphs" + // --- New: Topological Data Analysis Libraries --- + namespace Ripser < Library ; location &= "https://github.com/Ripser/ripser" + namespace GUDHI < Library ; location &= "https://github.com/GUDHI/gudhi-devel" + namespace Dionysus < Library ; location &= "https://github.com/mrzv/dionysus" + namespace JavaPlex < Library ; location &= "https://github.com/appliedtopology/javaplex" + namespace GiottoTDA | "Giotto-TDA" < Library ; location &= "https://github.com/giotto-ai/giotto-tda" + // --- New: Abstract Interpretation Libraries --- + namespace Crab < Library ; location &= "https://github.com/seahorn/crab" + // --- New: Quantum Computing Libraries --- + namespace AmazonBraket | "Amazon Braket SDK" < Library ; location &= "https://github.com/amazon-braket/amazon-braket-sdk-python" + // --- New: Biological Modeling Libraries --- + namespace Brian2 < Library ; location &= "https://github.com/brian-team/brian2" & "https://briansimulator.org/" + namespace NEST | "NEST Simulator" < Library ; location &= "https://github.com/nest/nest-simulator" & "https://www.nest-simulator.org/" & "https://en.wikipedia.org/wiki/NEST_(software)" + namespace PyNN < Library ; location &= "https://github.com/NeuralEnsemble/PyNN" & "https://neuralensemble.org/PyNN/" + namespace PySB < Library ; location &= "https://github.com/pysb/pysb" & "https://pysb.org/" + namespace COPASI < Library ; location &= "https://github.com/copasi/COPASI" & "https://copasi.org/" & "https://en.wikipedia.org/wiki/COPASI" + namespace GenJl | "Gen.jl" < Library ; location &= "https://github.com/probcomp/Gen.jl" & "https://www.gen.dev/" + // --- New: Simulation Libraries --- + namespace SimPy < Library ; location &= "https://gitlab.com/team-simpy/simpy" & "https://simpy.readthedocs.io/" + // --- New: Constraint Solving Libraries --- + namespace Gecode < Library ; location &= "https://github.com/Gecode/gecode" & "https://www.gecode.org/" & "https://en.wikipedia.org/wiki/Gecode" + namespace ORTools | "OR-Tools" < Library ; location &= "https://github.com/google/or-tools" & "https://developers.google.com/optimization" + namespace Choco | "Choco-solver" < Library ; location &= "https://github.com/chocoteam/choco-solver" & "https://choco-solver.org/" + // --- New: Semantic Web Libraries --- + namespace Protege < Library ; location &= "https://github.com/protegeproject/protege" & "https://protege.stanford.edu/" & "https://en.wikipedia.org/wiki/Prot%C3%A9g%C3%A9_(software)" + namespace ApacheJena | "Apache Jena" < Library ; location &= "https://github.com/apache/jena" & "https://jena.apache.org/" & "https://en.wikipedia.org/wiki/Apache_Jena" + namespace Oxigraph < Library ; location &= "https://github.com/oxigraph/oxigraph" + // --- New: Description Logic Reasoners --- + namespace HermiT < Library ; location &= "https://github.com/owlcs/hermit-reasoner" & "http://www.hermit-reasoner.com/" + namespace Pellet < Library ; location &= "https://github.com/stardog-union/pellet" & "https://en.wikipedia.org/wiki/Pellet_(reasoner)" + namespace ELK | "ELK Reasoner" < Library ; location &= "https://github.com/liveontologies/elk-reasoner" + // --- New: Hardware EDA Tools --- + namespace Hardcaml < Library ; location &= "https://github.com/janestreet/hardcaml" + namespace OpenROAD < Tool ; location &= "https://github.com/The-OpenROAD-Project/OpenROAD" & "https://theopenroadproject.org/" + namespace KLayout < Tool ; location &= "https://github.com/KLayout/klayout" & "https://www.klayout.de/" + namespace ngspice < Tool ; location &= "https://ngspice.sourceforge.io/" & "https://en.wikipedia.org/wiki/Ngspice" + namespace Magic | "Magic VLSI" < Tool ; location &= "https://github.com/RTimothyEdwards/magic" & "https://en.wikipedia.org/wiki/Magic_(software)" + // --- New: Semantic Web Libraries (additional) --- + namespace RDFLib < Library ; location &= "https://github.com/RDFLib/rdflib" & "https://rdflib.dev/" + namespace Blazegraph < Library ; location &= "https://github.com/blazegraph/database" & "https://en.wikipedia.org/wiki/Blazegraph" + namespace Stardog < Tool ; location &= "https://github.com/stardog-union" & "https://www.stardog.com/" + namespace GraphDB | "Ontotext GraphDB" < Tool ; location &= "https://graphdb.ontotext.com/" & "https://en.wikipedia.org/wiki/Ontotext_GraphDB" + namespace Virtuoso | "OpenLink Virtuoso" < Library ; location &= "https://github.com/openlink/virtuoso-opensource" & "https://en.wikipedia.org/wiki/Virtuoso_Universal_Server" + // --- New: Description Logic Reasoners (additional) --- + namespace FaCTPlusPlus | "FaCT++" < Library ; location &= "https://github.com/ethz-asl/libfactplusplus" & "http://owl.cs.manchester.ac.uk/tools/fact/" + namespace Konclude < Library ; location &= "https://github.com/konclude/Konclude" & "https://www.uni-ulm.de/en/konclude/" + namespace Racer | "RacerPro" < Library ; location &= "https://github.com/ha-mo-we/Racer" & "https://www.chai.uni-hamburg.de/~moeller/racer/" + // --- New: Rule Engine Libraries --- + namespace Jess < Library ; location &= "https://jess.sandia.gov/" & "https://en.wikipedia.org/wiki/Jess_(programming_language)" + namespace ClaraRules | "Clara Rules" < Library ; location &= "https://github.com/oracle-samples/clara-rules" & "http://www.clara-rules.org/" + // --- New: Simulation Libraries --- + namespace xDEVS < Library ; location &= "https://github.com/iscar-ucm/xdevs" & "https://en.wikipedia.org/wiki/DEVS" + namespace OscaR < Library ; location &= "https://github.com/cetic/oscar-cbls" & "https://oscarlib.readthedocs.io/" namespace Schurr1999 | "Schurr 1999" < Library ; location &= "https://link.springer.com/chapter/10.1007/978-3-540-68679-8_5" namespace "set.mm" < Library, SetTheory namespace UniMath < Library, TypeTheory.Univalent ; location &= this ? ("https://github.com/UniMath/agda-unimath" : "https://github.com/UniMath/UniMath") diff --git a/@ether/library/Index/__init__.py b/@ether/library/Index/__init__.py new file mode 100644 index 00000000..7c96bfa4 --- /dev/null +++ b/@ether/library/Index/__init__.py @@ -0,0 +1 @@ +# Ether.library.Index - Cross-Language Code Search & Comparison System diff --git a/@ether/library/Index/__main__.py b/@ether/library/Index/__main__.py new file mode 100644 index 00000000..efdb7531 --- /dev/null +++ b/@ether/library/Index/__main__.py @@ -0,0 +1,3 @@ +"""Allow running as: python -m Ether.library.Index.cli""" +from .cli import main +main() diff --git a/@ether/library/Index/api/__init__.py b/@ether/library/Index/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/@ether/library/Index/api/routes.py b/@ether/library/Index/api/routes.py new file mode 100644 index 00000000..cf580628 --- /dev/null +++ b/@ether/library/Index/api/routes.py @@ -0,0 +1,190 @@ +"""FastAPI endpoint handlers.""" +from __future__ import annotations + +from typing import Optional + +from fastapi import APIRouter, HTTPException +from pydantic import BaseModel + +router = APIRouter() + +# --- Request/Response Models --- + +class SearchRequest(BaseModel): + query: str + language: Optional[str] = None + version: Optional[str] = None + ast_type: Optional[str] = None + repo: Optional[str] = None + limit: int = 20 + +class FindEquivalentsRequest(BaseModel): + code: str + source_language: str + limit: int = 20 + rerank: bool = True + structural: bool = True + target_languages: Optional[list[str]] = None + +class CompareRequest(BaseModel): + code_a: str + language_a: str + code_b: str + language_b: str + +class IndexRequest(BaseModel): + languages: Optional[list[str]] = None + incremental: bool = True + +class ModelSelectRequest(BaseModel): + model: str + task: str # "indexing" or "reranking" + + +# --- Lazy-loaded shared state --- + +_state = {} + +def _get_state(): + """Lazy-initialize shared components.""" + if "initialized" in _state: + return _state + + from ..config import load_models_config + from ..models import ModelRegistry + from ..store.vector_store import VectorStore + from ..indexing.registry import LanguageRegistry + from ..indexing.chunker import Chunker + from ..models.embedder import CodeEmbedder + from ..indexing.pipeline import IndexingPipeline + from ..query.semantic import SemanticSearch + from ..query.cross_lang import CrossLanguageFinder + + registry = LanguageRegistry() + registry.load() + + model_registry = ModelRegistry() + store = VectorStore() + + _state["registry"] = registry + _state["model_registry"] = model_registry + _state["store"] = store + + # Try to load models - may fail if weights not downloaded + try: + index_model = model_registry.get_indexing_model() + _state["search"] = SemanticSearch(index_model, store) + _state["embedder"] = CodeEmbedder(index_model) + + rerank_model = None + try: + rerank_model = model_registry.get_reranking_model() + except Exception: + pass + _state["cross_lang"] = CrossLanguageFinder(index_model, store, rerank_model) + + _state["pipeline"] = IndexingPipeline( + registry=registry, + embedder=CodeEmbedder(index_model), + store=store, + chunker=Chunker(), + ) + except Exception as e: + _state["model_error"] = str(e) + + _state["initialized"] = True + return _state + + +# --- Endpoints --- + +@router.get("/health") +async def health(): + return {"status": "ok"} + + +@router.post("/search") +async def search(req: SearchRequest): + state = _get_state() + if "search" not in state: + raise HTTPException(503, detail=f"Models not loaded: {state.get('model_error', 'unknown')}") + + results = state["search"].search( + query=req.query, + limit=req.limit, + language=req.language, + version=req.version, + ast_type=req.ast_type, + repo=req.repo, + ) + return {"results": [r.to_dict() for r in results]} + + +@router.post("/find-equivalents") +async def find_equivalents(req: FindEquivalentsRequest): + state = _get_state() + if "cross_lang" not in state: + raise HTTPException(503, detail=f"Models not loaded: {state.get('model_error', 'unknown')}") + + result = state["cross_lang"].find_equivalents( + code=req.code, + source_language=req.source_language, + limit=req.limit, + rerank=req.rerank, + structural=req.structural, + target_languages=req.target_languages, + ) + return result.to_dict() + + +@router.post("/compare") +async def compare_code(req: CompareRequest): + from ..query.structural import compare + result = compare(req.code_a, req.language_a, req.code_b, req.language_b) + return result.to_dict() + + +@router.get("/languages") +async def list_languages(): + state = _get_state() + return {"languages": state["store"].languages()} + + +@router.post("/index") +async def trigger_index(req: IndexRequest): + state = _get_state() + if "pipeline" not in state: + raise HTTPException(503, detail=f"Models not loaded: {state.get('model_error', 'unknown')}") + + results = state["pipeline"].index_all( + incremental=req.incremental, + languages=req.languages, + ) + return {"results": results} + + +@router.get("/models") +async def list_models(): + state = _get_state() + mr = state["model_registry"] + return { + "indexing": mr.indexing_model_name, + "reranking": mr.reranking_model_name, + "models": mr.list_models(), + } + + +@router.post("/models/select") +async def select_model(req: ModelSelectRequest): + state = _get_state() + try: + state["model_registry"].select(req.model, req.task) + except (KeyError, ValueError) as e: + raise HTTPException(400, detail=str(e)) + return {"status": "ok", "task": req.task, "model": req.model} + + +@router.get("/stats") +async def stats(): + state = _get_state() + return state["store"].stats() diff --git a/@ether/library/Index/api/server.py b/@ether/library/Index/api/server.py new file mode 100644 index 00000000..b85acb84 --- /dev/null +++ b/@ether/library/Index/api/server.py @@ -0,0 +1,25 @@ +"""FastAPI app and uvicorn launcher.""" +from __future__ import annotations + +from ..config import DEFAULT_API_HOST, DEFAULT_API_PORT + + +def create_app(): + """Create the FastAPI application.""" + from fastapi import FastAPI + from .routes import router + + app = FastAPI( + title="Ether Code Index", + description="Cross-language code search and comparison API", + version="0.1.0", + ) + app.include_router(router, prefix="/api") + return app + + +def run(host: str = DEFAULT_API_HOST, port: int = DEFAULT_API_PORT): + """Start the API server.""" + import uvicorn + app = create_app() + uvicorn.run(app, host=host, port=port) diff --git a/@ether/library/Index/cli.py b/@ether/library/Index/cli.py new file mode 100644 index 00000000..278f3b21 --- /dev/null +++ b/@ether/library/Index/cli.py @@ -0,0 +1,285 @@ +"""CLI entry point for ./ether Language ... commands. + +Usage: + python -m Ether.library.Index.cli Language.Python index + python -m Ether.library.Index.cli Language search "binary search tree" + python -m Ether.library.Index.cli Language server + python -m Ether.library.Index.cli Language stats + python -m Ether.library.Index.cli Language models +""" +from __future__ import annotations + +import argparse +import json +import sys + + +def main(argv: list[str] | None = None): + args = argv or sys.argv[1:] + + if not args: + _print_usage() + sys.exit(1) + + command = args[0] + rest = args[1:] + + if command == "index": + _cmd_index(rest) + elif command == "search": + _cmd_search(rest) + elif command == "server": + _cmd_server(rest) + elif command == "stats": + _cmd_stats(rest) + elif command == "models": + _cmd_models(rest) + else: + print(f"Unknown command: {command}", file=sys.stderr) + _print_usage() + sys.exit(1) + + +def _print_usage(): + print("Usage: ether Language [options]") + print() + print("Commands:") + print(" index [--lang NAME] [--version VER] [--full] Index source code") + print(" search [--lang NAME] [--limit N] Search code") + print(" search --file PATH --cross-lang Find equivalents") + print(" server [--port PORT] Start API server") + print(" stats Show index statistics") + print(" models [--use NAME --for TASK] List/switch models") + + +def _cmd_index(args: list[str]): + parser = argparse.ArgumentParser(prog="ether Language index") + parser.add_argument("--lang", help="Language to index (default: all)") + parser.add_argument("--version", help="Version override") + parser.add_argument("--full", action="store_true", help="Full reindex (not incremental)") + parser.add_argument("--max-files", type=int, default=0, help="Max files to index (0=all)") + opts = parser.parse_args(args) + + from .config import ensure_dirs + from .models import ModelRegistry + from .models.embedder import CodeEmbedder + from .store.vector_store import VectorStore + from .indexing.registry import LanguageRegistry + from .indexing.chunker import Chunker + from .indexing.pipeline import IndexingPipeline + + ensure_dirs() + registry = LanguageRegistry() + registry.load() + + model_registry = ModelRegistry() + try: + index_model = model_registry.get_indexing_model() + except Exception as e: + print(f"Error loading model: {e}", file=sys.stderr) + print("Download model weights first. See README for instructions.", file=sys.stderr) + sys.exit(1) + + embedder = CodeEmbedder(index_model) + store = VectorStore() + pipeline = IndexingPipeline( + registry=registry, embedder=embedder, store=store, chunker=Chunker(), + ) + + def progress(phase, cur, tot): + if tot > 0: + print(f"\r {phase}: {cur}/{tot}", end="", flush=True) + else: + print(f"\r {phase}...", end="", flush=True) + + if opts.lang: + print(f"Indexing {opts.lang}...") + result = pipeline.index_language( + opts.lang, version=opts.version, + incremental=not opts.full, max_files=opts.max_files, + progress_callback=progress, + ) + print() + print(f" Files: {result.get('files', 0)}") + print(f" Chunks: {result.get('chunks', 0)}") + if result.get("version"): + print(f" Version: {result['version']}") + else: + print("Indexing all languages...") + def lang_progress(lang, phase, cur, tot): + if tot > 0: + print(f"\r [{lang}] {phase}: {cur}/{tot}", end="", flush=True) + + results = pipeline.index_all(incremental=not opts.full, progress_callback=lang_progress) + print() + total_files = sum(r.get("files", 0) for r in results) + total_chunks = sum(r.get("chunks", 0) for r in results) + indexed = [r for r in results if r.get("chunks", 0) > 0] + print(f" Languages indexed: {len(indexed)}") + print(f" Total files: {total_files}") + print(f" Total chunks: {total_chunks}") + + +def _cmd_search(args: list[str]): + parser = argparse.ArgumentParser(prog="ether Language search") + parser.add_argument("query", nargs="?", help="Search query") + parser.add_argument("--lang", help="Filter to language") + parser.add_argument("--version", help="Filter to version") + parser.add_argument("--limit", type=int, default=20, help="Max results") + parser.add_argument("--file", help="File to find equivalents for") + parser.add_argument("--cross-lang", action="store_true", help="Cross-language search") + parser.add_argument("--rerank", action="store_true", help="Rerank results with larger model") + opts = parser.parse_args(args) + + if not opts.query and not opts.file: + print("Error: provide a query or --file", file=sys.stderr) + sys.exit(1) + + from .models import ModelRegistry + from .store.vector_store import VectorStore + from .query.semantic import SemanticSearch + from .query.cross_lang import CrossLanguageFinder + + model_registry = ModelRegistry() + try: + index_model = model_registry.get_indexing_model() + except Exception as e: + print(f"Error loading model: {e}", file=sys.stderr) + sys.exit(1) + + store = VectorStore() + + if opts.file: + # Cross-language equivalence search + from pathlib import Path + code = Path(opts.file).read_text() + # Try to detect language from extension + ext = Path(opts.file).suffix + from .indexing.registry import LanguageRegistry + reg = LanguageRegistry() + reg.load() + ext_map = reg.build_extension_map() + source_lang = ext_map.get(ext, ["Unknown"])[0] if ext in ext_map else "Unknown" + if opts.lang: + source_lang = opts.lang + + rerank_model = None + try: + rerank_model = model_registry.get_reranking_model() + except Exception: + pass + + finder = CrossLanguageFinder(index_model, store, rerank_model) + result = finder.find_equivalents( + code=code, source_language=source_lang, + limit=opts.limit, rerank=rerank_model is not None, + ) + print(f"Equivalents for {source_lang} code ({len(result.equivalents)} found):") + for r in result.equivalents: + print(f" {r.summary()}") + else: + if opts.rerank: + # Load reranking model and use CrossLanguageFinder + rerank_model = None + try: + print("Loading reranking model...", flush=True) + rerank_model = model_registry.get_reranking_model() + except Exception as e: + print(f"Warning: Could not load reranking model: {e}", file=sys.stderr) + print("Falling back to standard search.", file=sys.stderr) + + if rerank_model and rerank_model is not index_model: + finder = CrossLanguageFinder(index_model, store, rerank_model) + result = finder.find_equivalents( + code=opts.query, source_language="__query__", + limit=opts.limit, rerank=True, structural=False, + target_languages=[opts.lang] if opts.lang else None, + ) + results = result.equivalents + else: + search = SemanticSearch(index_model, store) + results = search.search( + query=opts.query, limit=opts.limit, + language=opts.lang, version=opts.version, + ) + else: + search = SemanticSearch(index_model, store) + results = search.search( + query=opts.query, limit=opts.limit, + language=opts.lang, version=opts.version, + ) + print(f"Results ({len(results)} found):") + for r in results: + print(f" {r.summary()}") + if len(r.text) > 200: + print(f" {r.text[:200]}...") + else: + print(f" {r.text}") + print() + + +def _cmd_server(args: list[str]): + parser = argparse.ArgumentParser(prog="ether Language server") + parser.add_argument("--port", type=int, default=8420, help="Port (default: 8420)") + parser.add_argument("--host", default="0.0.0.0", help="Host (default: 0.0.0.0)") + opts = parser.parse_args(args) + + print(f"Starting Ether Code Index API on {opts.host}:{opts.port}") + from .api.server import run + run(host=opts.host, port=opts.port) + + +def _cmd_stats(args: list[str]): + from .store.vector_store import VectorStore + store = VectorStore() + stats = store.stats() + print("Index Statistics:") + print(f" Total chunks: {stats.get('total_chunks', 0):,}") + print(f" Languages: {stats.get('languages', 0)}") + print(f" Repos: {stats.get('repos', 0)}") + + if stats.get("total_chunks", 0) > 0: + print() + print("Per-language:") + for entry in store.languages(): + print(f" {entry['language']}: {entry['count']:,} chunks") + + +def _cmd_models(args: list[str]): + parser = argparse.ArgumentParser(prog="ether Language models") + parser.add_argument("--use", help="Model name to switch to") + parser.add_argument("--for", dest="task", choices=["index", "rerank"], help="Task to assign model to") + opts = parser.parse_args(args) + + from .models import ModelRegistry + mr = ModelRegistry() + + if opts.use and opts.task: + task_name = "indexing" if opts.task == "index" else "reranking" + try: + mr.select(opts.use, task_name) + print(f"Switched {task_name} model to: {opts.use}") + except (KeyError, ValueError) as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) + elif opts.use or opts.task: + print("Error: --use and --for must both be specified", file=sys.stderr) + sys.exit(1) + else: + config = mr.config + print("Models:") + print(f" Indexing: {config.get('indexing', 'none')}") + print(f" Reranking: {config.get('reranking', 'none')}") + print() + print("Available models:") + for name, info in config.get("models", {}).items(): + marker = "" + if name == config.get("indexing"): + marker += " [indexing]" + if name == config.get("reranking"): + marker += " [reranking]" + print(f" {name} ({info.get('size', '?')}){marker}") + + +if __name__ == "__main__": + main() diff --git a/@ether/library/Index/config.py b/@ether/library/Index/config.py new file mode 100644 index 00000000..8d25e001 --- /dev/null +++ b/@ether/library/Index/config.py @@ -0,0 +1,115 @@ +"""Paths, constants, and configuration for the Index system.""" +import json +from pathlib import Path + +# Root of the project (where ./ether lives) +PROJECT_ROOT = Path(__file__).resolve().parents[3] + +# Core paths +ETHER_DIR = PROJECT_ROOT / ".ether" +CACHE_DIR = ETHER_DIR / "cache" +INDEX_TSV = CACHE_DIR / "index.tsv" +EXTERNAL_DIR = ETHER_DIR / "external" +LANG_SCRIPTS_DIR = PROJECT_ROOT / "Ether" / "library" / "Language" + +# Index storage paths +INDEX_DIR = ETHER_DIR / "index" +VECTORS_DIR = INDEX_DIR / "vectors" +MODELS_DIR = INDEX_DIR / "models" +MODELS_CONFIG = INDEX_DIR / "models.json" +STATE_DIR = INDEX_DIR / "state" +INDEX_STATE_FILE = STATE_DIR / "index_state.json" + +# Tinygrad reference models (for LLaMA) +TINYGRAD_DIR = PROJECT_ROOT / ".orbitmines" / "external" / "github.com" / "tinygrad" / "tinygrad" + +# Embedding dimensions +EMBEDDING_DIM = 768 + +# Indexing defaults +DEFAULT_BATCH_SIZE = 256 +DEFAULT_CHUNK_MAX_LINES = 100 +DEFAULT_CHUNK_MIN_LINES = 5 + +# API defaults +DEFAULT_API_HOST = "0.0.0.0" +DEFAULT_API_PORT = 8420 + +# Search defaults +DEFAULT_SEARCH_LIMIT = 20 +DEFAULT_RERANK_CANDIDATES = 100 + +# Default model config +DEFAULT_MODELS_CONFIG = { + "indexing": "coderank-embed-tinygrad", + "reranking": "nomic-embed-code-7b", + "models": { + "coderank-embed": { + "type": "sentence_transformer", + "hf_name": "nomic-ai/CodeRankEmbed", + "path": "", + "size": "137M", + "hidden_size": 768, + "max_position_embeddings": 8192, + "query_prefix": "search_query: ", + "document_prefix": "search_document: ", + }, + "nomic-embed-code-7b": { + "type": "sentence_transformer", + "hf_name": "nomic-ai/nomic-embed-code", + "path": "", + "size": "7B", + "hidden_size": 3584, + "max_position_embeddings": 8192, + "query_prefix": "search_query: ", + "document_prefix": "search_document: ", + "pooling": "last_token", + }, + "coderank-embed-tinygrad": { + "type": "nomic_bert", + "path": str(MODELS_DIR / "CodeRankEmbed"), + "size": "137M", + "hidden_size": 768, + "intermediate_size": 3072, + "num_attention_heads": 12, + "num_hidden_layers": 12, + "max_position_embeddings": 8192, + "vocab_size": 30528, + "rotary_emb_fraction": 1.0, + "rotary_emb_base": 1000, + "query_prefix": "search_query: ", + "document_prefix": "search_document: ", + }, + "llama-3-8b": { + "type": "llama", + "path": "", + "size": "8B", + }, + }, +} + +# File extension to language mapping (populated from index.tsv at runtime) +EXTENSION_MAP: dict[str, list[str]] = {} + + +def ensure_dirs(): + """Create required directories if they don't exist.""" + for d in [INDEX_DIR, VECTORS_DIR, MODELS_DIR, STATE_DIR]: + d.mkdir(parents=True, exist_ok=True) + + +def load_models_config() -> dict: + """Load model configuration, creating default if needed.""" + ensure_dirs() + if MODELS_CONFIG.exists(): + with open(MODELS_CONFIG) as f: + return json.load(f) + save_models_config(DEFAULT_MODELS_CONFIG) + return DEFAULT_MODELS_CONFIG.copy() + + +def save_models_config(config: dict): + """Save model configuration.""" + ensure_dirs() + with open(MODELS_CONFIG, "w") as f: + json.dump(config, f, indent=2) diff --git a/@ether/library/Index/indexing/__init__.py b/@ether/library/Index/indexing/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/@ether/library/Index/indexing/chunker.py b/@ether/library/Index/indexing/chunker.py new file mode 100644 index 00000000..2b94ef11 --- /dev/null +++ b/@ether/library/Index/indexing/chunker.py @@ -0,0 +1,42 @@ +"""Chunking facade - picks tree-sitter or line-based fallback.""" +from __future__ import annotations + +from .tree_sitter_chunker import TreeSitterChunker, CodeChunk +from .line_chunker import LineChunker +from ..config import DEFAULT_CHUNK_MAX_LINES, DEFAULT_CHUNK_MIN_LINES + + +class Chunker: + """Facade that selects the best chunking strategy for a given language.""" + + def __init__(self, min_lines: int = DEFAULT_CHUNK_MIN_LINES, + max_lines: int = DEFAULT_CHUNK_MAX_LINES): + self.min_lines = min_lines + self.max_lines = max_lines + self._ts_chunker = TreeSitterChunker() + self._line_chunker = LineChunker() + + def chunk(self, source: str, language: str) -> list[CodeChunk]: + """Chunk source code using the best available strategy. + + Uses tree-sitter AST parsing for supported languages, + falls back to blank-line-boundary splitting otherwise. + + Args: + source: Source code text. + language: Language name (e.g. "Python", "Rust"). + + Returns: + List of CodeChunk objects. + """ + if self._ts_chunker.supports(language): + chunks = self._ts_chunker.chunk(source, language, self.min_lines, self.max_lines) + if chunks: + return chunks + + # Fallback to line-based + return self._line_chunker.chunk(source, self.min_lines, self.max_lines) + + def supported_languages(self) -> list[str]: + """Return languages with tree-sitter support.""" + return self._ts_chunker.supported_languages() diff --git a/@ether/library/Index/indexing/crawler.py b/@ether/library/Index/indexing/crawler.py new file mode 100644 index 00000000..9ccb041e --- /dev/null +++ b/@ether/library/Index/indexing/crawler.py @@ -0,0 +1,117 @@ +"""Walk .ether/external/ to discover source files for indexing.""" +from __future__ import annotations + +import os +from dataclasses import dataclass +from pathlib import Path + +from .registry import LanguageEntry + +# Directories to skip during crawling +SKIP_DIRS = { + ".git", ".hg", ".svn", "node_modules", "__pycache__", ".tox", + ".eggs", "*.egg-info", "vendor", "third_party", "dist", "build", + ".cache", ".mypy_cache", ".pytest_cache", ".ruff_cache", +} + +# Max file size to index (1MB) +MAX_FILE_SIZE = 1_000_000 + + +@dataclass +class SourceFile: + """A discovered source file ready for chunking.""" + path: Path + language: str + repo: str + relative_path: str # Path relative to the repo root + + +class SourceCrawler: + """Discovers source files in cloned repos.""" + + def __init__(self, extension_map: dict[str, list[str]]): + """ + Args: + extension_map: Map from file extension (e.g. '.py') to language names. + """ + self._ext_map = extension_map + # Build reverse: set of all known extensions for fast lookup + self._known_exts = set(extension_map.keys()) + + def crawl_entry(self, entry: LanguageEntry) -> list[SourceFile]: + """Crawl a single language entry's repo.""" + repo_path = entry.repo_path + if repo_path is None or not repo_path.exists(): + return [] + + # Derive the repo identifier from github_url + repo_id = entry.github_url.rstrip("/") + if repo_id.startswith("https://"): + repo_id = repo_id[len("https://"):] + + files = [] + for source_file in self._walk_dir(repo_path, entry.name, repo_id): + files.append(source_file) + return files + + def crawl_entries(self, entries: list[LanguageEntry]) -> list[SourceFile]: + """Crawl multiple language entries' repos.""" + files = [] + for entry in entries: + files.extend(self.crawl_entry(entry)) + return files + + def _walk_dir(self, root: Path, language: str, repo: str) -> list[SourceFile]: + """Walk directory tree, yielding matching source files.""" + results = [] + for dirpath, dirnames, filenames in os.walk(root): + # Prune skipped directories in-place + dirnames[:] = [ + d for d in dirnames + if d not in SKIP_DIRS and not d.endswith(".egg-info") + ] + + for fname in filenames: + fpath = Path(dirpath) / fname + ext = self._get_extension(fname) + if ext not in self._known_exts: + continue + + # Check this extension maps to the expected language + langs_for_ext = self._ext_map.get(ext, []) + if language not in langs_for_ext: + continue + + # Skip files that are too large + try: + if fpath.stat().st_size > MAX_FILE_SIZE: + continue + except OSError: + continue + + rel_path = str(fpath.relative_to(root)) + results.append(SourceFile( + path=fpath, + language=language, + repo=repo, + relative_path=rel_path, + )) + return results + + @staticmethod + def _get_extension(filename: str) -> str: + """Get file extension including the dot, handling compound extensions.""" + # Handle compound extensions like .ray.txt + name = filename + exts = [] + while True: + base, ext = os.path.splitext(name) + if not ext: + break + exts.insert(0, ext) + name = base + # Return the primary extension (last one) + if exts: + return exts[-1] + return "" diff --git a/@ether/library/Index/indexing/line_chunker.py b/@ether/library/Index/indexing/line_chunker.py new file mode 100644 index 00000000..92a14371 --- /dev/null +++ b/@ether/library/Index/indexing/line_chunker.py @@ -0,0 +1,93 @@ +"""Fallback line-based chunking for languages without tree-sitter support. + +Splits source code on blank-line boundaries into chunks. +""" +from __future__ import annotations + +from dataclasses import dataclass + +from .tree_sitter_chunker import CodeChunk + + +class LineChunker: + """Splits source code into chunks at blank-line boundaries.""" + + def chunk(self, source: str, min_lines: int = 5, max_lines: int = 100) -> list[CodeChunk]: + """Split source into chunks at blank-line boundaries. + + Args: + source: Source code text. + min_lines: Minimum chunk size in lines. + max_lines: Maximum chunk size in lines. + + Returns: + List of CodeChunk objects. + """ + if not source.strip(): + return [] + + lines = source.split("\n") + chunks = [] + current_start = 0 + current_lines: list[str] = [] + blank_count = 0 + + for i, line in enumerate(lines): + stripped = line.strip() + if not stripped: + blank_count += 1 + current_lines.append(line) + # Split at double blank lines, or if we've exceeded max_lines + if (blank_count >= 2 or len(current_lines) >= max_lines) and len(current_lines) >= min_lines: + text = "\n".join(current_lines).rstrip() + if text.strip(): + chunks.append(CodeChunk( + text=text, + start_line=current_start + 1, + end_line=current_start + len(current_lines), + ast_type="block", + name="", + )) + current_start = i + 1 + current_lines = [] + blank_count = 0 + else: + blank_count = 0 + current_lines.append(line) + + # Force split at max_lines + if len(current_lines) >= max_lines: + text = "\n".join(current_lines) + chunks.append(CodeChunk( + text=text, + start_line=current_start + 1, + end_line=current_start + len(current_lines), + ast_type="block", + name="", + )) + current_start = i + 1 + current_lines = [] + blank_count = 0 + + # Don't forget the last chunk + if current_lines: + text = "\n".join(current_lines).rstrip() + if text.strip() and len(current_lines) >= min_lines: + chunks.append(CodeChunk( + text=text, + start_line=current_start + 1, + end_line=current_start + len(current_lines), + ast_type="block", + name="", + )) + elif text.strip() and not chunks: + # If this is the only content and it's too small, include it anyway + chunks.append(CodeChunk( + text=text, + start_line=current_start + 1, + end_line=current_start + len(current_lines), + ast_type="block", + name="", + )) + + return chunks diff --git a/@ether/library/Index/indexing/pipeline.py b/@ether/library/Index/indexing/pipeline.py new file mode 100644 index 00000000..0c259980 --- /dev/null +++ b/@ether/library/Index/indexing/pipeline.py @@ -0,0 +1,267 @@ +"""Indexing pipeline orchestrator: crawl -> chunk -> embed -> store.""" +from __future__ import annotations + +import json +import time +import uuid +from pathlib import Path +from typing import Callable + +from ..config import INDEX_STATE_FILE, ensure_dirs +from ..models.embedder import CodeEmbedder +from ..store.vector_store import VectorStore +from .registry import LanguageRegistry, LanguageEntry +from .crawler import SourceCrawler, SourceFile +from .chunker import Chunker +from .tree_sitter_chunker import CodeChunk + + +class IndexState: + """Tracks which files have been indexed.""" + + def __init__(self, state_file: Path | None = None): + self._file = state_file or INDEX_STATE_FILE + self._state: dict = {} + self._load() + + def _load(self): + if self._file.exists(): + with open(self._file) as f: + self._state = json.load(f) + else: + self._state = {"files": {}, "languages": {}} + + def save(self): + ensure_dirs() + with open(self._file, "w") as f: + json.dump(self._state, f, indent=2) + + def is_indexed(self, file_path: str, mtime: float) -> bool: + """Check if a file has been indexed (and hasn't changed).""" + entry = self._state.get("files", {}).get(file_path) + if entry is None: + return False + return entry.get("mtime", 0) >= mtime + + def mark_indexed(self, file_path: str, mtime: float, chunk_count: int): + self._state.setdefault("files", {})[file_path] = { + "mtime": mtime, + "chunks": chunk_count, + "indexed_at": time.time(), + } + + def mark_language(self, language: str, version: str, file_count: int, chunk_count: int): + self._state.setdefault("languages", {})[language] = { + "version": version, + "files": file_count, + "chunks": chunk_count, + "indexed_at": time.time(), + } + + def get_language_info(self, language: str) -> dict | None: + return self._state.get("languages", {}).get(language) + + +class IndexingPipeline: + """Orchestrates the full indexing pipeline.""" + + def __init__( + self, + registry: LanguageRegistry, + embedder: CodeEmbedder, + store: VectorStore, + chunker: Chunker | None = None, + state: IndexState | None = None, + ): + self.registry = registry + self.embedder = embedder + self.store = store + self.chunker = chunker or Chunker() + self.state = state or IndexState() + self._ext_map = registry.build_extension_map() + self._crawler = SourceCrawler(self._ext_map) + + def index_language( + self, + language_name: str, + version: str | None = None, + incremental: bool = True, + max_files: int = 0, + progress_callback: Callable[[str, int, int], None] | None = None, + ) -> dict: + """Index a single language. + + Args: + language_name: Name of the language to index. + version: Override version string. + incremental: Skip already-indexed files. + progress_callback: Called with (phase, current, total). + + Returns: + Dict with indexing stats. + """ + entry = self.registry.get(language_name) + if entry is None: + raise ValueError(f"Unknown language: {language_name}") + + if not entry.has_repo: + return {"language": language_name, "error": "No repo cloned", "files": 0, "chunks": 0} + + entry.version = version or entry.resolve_version() + + if not incremental: + self.store.delete_by_language(entry.name) + + # Phase 1: Crawl + if progress_callback: + progress_callback("crawling", 0, 0) + source_files = self._crawler.crawl_entry(entry) + + if not source_files: + return {"language": language_name, "files": 0, "chunks": 0} + + # Filter out already-indexed files + if incremental: + source_files = self._filter_new(source_files) + + if not source_files: + return {"language": language_name, "files": 0, "chunks": 0, "skipped": "all up to date"} + + if max_files > 0: + source_files = source_files[:max_files] + + # Phase 2: Chunk + if progress_callback: + progress_callback("chunking", 0, len(source_files)) + + all_chunks: list[tuple[SourceFile, CodeChunk]] = [] + for i, sf in enumerate(source_files): + try: + source = sf.path.read_text(errors="replace") + except (OSError, UnicodeDecodeError): + continue + chunks = self.chunker.chunk(source, sf.language) + for chunk in chunks: + all_chunks.append((sf, chunk)) + if progress_callback: + progress_callback("chunking", i + 1, len(source_files)) + + if not all_chunks: + return {"language": language_name, "files": len(source_files), "chunks": 0} + + # Phase 3+4: Embed and store in streaming batches + if hasattr(self.embedder.model, 'set_mode'): + self.embedder.model.set_mode('document') + + total_chunks = len(all_chunks) + if progress_callback: + progress_callback("embedding", 0, total_chunks) + + batch_size = self.embedder.batch_size + stored_count = 0 + t0 = time.time() + + for batch_start in range(0, total_chunks, batch_size): + batch_items = all_chunks[batch_start : batch_start + batch_size] + batch_texts = [chunk.text for _, chunk in batch_items] + + batch_embeddings = self.embedder.embed_batch(batch_texts) + + # Build records and store immediately + records = [] + for (sf, chunk), embedding in zip(batch_items, batch_embeddings): + records.append({ + "chunk_id": str(uuid.uuid4()), + "language": sf.language, + "version": entry.version, + "file_path": sf.relative_path, + "repo": sf.repo, + "start_line": chunk.start_line, + "end_line": chunk.end_line, + "ast_type": chunk.ast_type, + "name": chunk.name, + "text": chunk.text, + "vector": embedding.tolist(), + }) + self.store.insert(records) + stored_count += len(records) + + if progress_callback: + progress_callback("embedding", stored_count, total_chunks) + + # Print ETA after first batch + if batch_start == 0 and total_chunks > batch_size: + elapsed = time.time() - t0 + eta_sec = elapsed * (total_chunks / len(batch_items) - 1) + if eta_sec > 60: + print(f" (ETA: {eta_sec/60:.0f}m for {total_chunks} chunks)", flush=True) + else: + print(f" (ETA: {eta_sec:.0f}s for {total_chunks} chunks)", flush=True) + + # Update state + for sf in source_files: + try: + mtime = sf.path.stat().st_mtime + except OSError: + mtime = 0 + self.state.mark_indexed(sf.relative_path, mtime, len([ + c for s, c in all_chunks if s is sf + ])) + + self.state.mark_language(entry.name, entry.version, len(source_files), stored_count) + self.state.save() + + if progress_callback: + progress_callback("done", stored_count, stored_count) + + return { + "language": language_name, + "version": entry.version, + "files": len(source_files), + "chunks": stored_count, + } + + def index_all( + self, + incremental: bool = True, + languages: list[str] | None = None, + progress_callback: Callable[[str, str, int, int], None] | None = None, + ) -> list[dict]: + """Index all languages (or a subset). + + Args: + incremental: Skip already-indexed files. + languages: Optional list of language names to index. + progress_callback: Called with (language, phase, current, total). + + Returns: + List of per-language result dicts. + """ + if languages: + entries = [self.registry.get(name) for name in languages] + entries = [e for e in entries if e is not None and e.has_repo] + else: + entries = self.registry.with_repos() + + results = [] + for entry in entries: + lang_cb = None + if progress_callback: + lang_cb = lambda phase, cur, tot, lang=entry.name: progress_callback(lang, phase, cur, tot) + + result = self.index_language(entry.name, incremental=incremental, progress_callback=lang_cb) + results.append(result) + + return results + + def _filter_new(self, files: list[SourceFile]) -> list[SourceFile]: + """Filter out files that haven't changed since last indexing.""" + new_files = [] + for sf in files: + try: + mtime = sf.path.stat().st_mtime + except OSError: + continue + if not self.state.is_indexed(sf.relative_path, mtime): + new_files.append(sf) + return new_files diff --git a/@ether/library/Index/indexing/registry.py b/@ether/library/Index/indexing/registry.py new file mode 100644 index 00000000..4c50dd55 --- /dev/null +++ b/@ether/library/Index/indexing/registry.py @@ -0,0 +1,148 @@ +"""Parse index.tsv into LanguageEntry objects.""" +from __future__ import annotations + +import subprocess +from dataclasses import dataclass, field +from pathlib import Path + +from ..config import INDEX_TSV, EXTERNAL_DIR + + +@dataclass +class LanguageEntry: + name: str + aliases: str + category: str + extensions: list[str] + urls: list[str] + github_url: str + dir_name: str + version: str = "" + + @property + def repo_path(self) -> Path | None: + """Path to the cloned repo in .ether/external/.""" + if not self.github_url: + return None + # github.com/owner/repo -> .ether/external/github.com/owner/repo + url = self.github_url.rstrip("/") + if url.startswith("https://"): + url = url[len("https://"):] + return EXTERNAL_DIR / url + + @property + def has_repo(self) -> bool: + p = self.repo_path + return p is not None and p.exists() + + def resolve_version(self) -> str: + """Resolve version from git tag or commit SHA.""" + if self.version: + return self.version + repo = self.repo_path + if repo is None or not repo.exists(): + return "unknown" + try: + result = subprocess.run( + ["git", "describe", "--tags", "--abbrev=0"], + cwd=repo, capture_output=True, text=True, timeout=5, + ) + if result.returncode == 0 and result.stdout.strip(): + return result.stdout.strip() + except (subprocess.TimeoutExpired, FileNotFoundError): + pass + try: + result = subprocess.run( + ["git", "rev-parse", "--short", "HEAD"], + cwd=repo, capture_output=True, text=True, timeout=5, + ) + if result.returncode == 0 and result.stdout.strip(): + return result.stdout.strip() + except (subprocess.TimeoutExpired, FileNotFoundError): + pass + return "unknown" + + +class LanguageRegistry: + """Parses index.tsv and provides lookup by name/alias.""" + + def __init__(self, tsv_path: Path | None = None): + self.tsv_path = tsv_path or INDEX_TSV + self.entries: list[LanguageEntry] = [] + self._by_name: dict[str, LanguageEntry] = {} + self._by_dir_name: dict[str, LanguageEntry] = {} + + def load(self) -> list[LanguageEntry]: + """Parse the TSV file into LanguageEntry objects.""" + self.entries = [] + self._by_name = {} + self._by_dir_name = {} + + if not self.tsv_path.exists(): + raise FileNotFoundError(f"Index TSV not found: {self.tsv_path}") + + with open(self.tsv_path) as f: + for line in f: + line = line.rstrip("\n") + if not line: + continue + # TSV format: name\taliases\tcategory\textensions\turls\tgithub_url\tdir_name + # Use split with explicit tab - fields may be empty + parts = line.split("\t") + while len(parts) < 7: + parts.append("") + + name = parts[0] + aliases = parts[1] + category = parts[2] + extensions = [e.strip() for e in parts[3].split(",") if e.strip()] + urls = [u.strip() for u in parts[4].split(",") if u.strip()] + github_url = parts[5].strip() + dir_name = parts[6].strip() + + entry = LanguageEntry( + name=name, + aliases=aliases, + category=category, + extensions=extensions, + urls=urls, + github_url=github_url, + dir_name=dir_name, + ) + self.entries.append(entry) + self._by_name[name.lower()] = entry + if dir_name: + self._by_dir_name[dir_name.lower()] = entry + # Also index by aliases + if aliases: + for alias in aliases.split(","): + alias = alias.strip() + if alias: + self._by_name[alias.lower()] = entry + + return self.entries + + def get(self, name: str) -> LanguageEntry | None: + """Look up a language by name, alias, or dir_name.""" + key = name.lower() + return self._by_name.get(key) or self._by_dir_name.get(key) + + def languages(self) -> list[LanguageEntry]: + """Return only Language category entries.""" + return [e for e in self.entries if e.category == "Language"] + + def with_repos(self) -> list[LanguageEntry]: + """Return entries that have cloned repos.""" + return [e for e in self.entries if e.has_repo] + + def with_extensions(self) -> list[LanguageEntry]: + """Return entries that have file extensions defined.""" + return [e for e in self.entries if e.extensions] + + def build_extension_map(self) -> dict[str, list[str]]: + """Build a map from file extension to language names.""" + ext_map: dict[str, list[str]] = {} + for entry in self.entries: + for ext in entry.extensions: + ext_map.setdefault(ext, []).append(entry.name) + return ext_map diff --git a/@ether/library/Index/indexing/tree_sitter_chunker.py b/@ether/library/Index/indexing/tree_sitter_chunker.py new file mode 100644 index 00000000..52fb2e18 --- /dev/null +++ b/@ether/library/Index/indexing/tree_sitter_chunker.py @@ -0,0 +1,231 @@ +"""AST-based code chunking using tree-sitter. + +Parses source files into semantic chunks (functions, classes, methods, etc.) +using tree-sitter grammars for 150+ languages. +""" +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path + +# Language name -> tree-sitter language module name +_LANG_TO_TS = { + "Python": "python", + "JavaScript": "javascript", + "TypeScript": "typescript", + "Rust": "rust", + "C": "c", + "C++": "cpp", + "Go": "go", + "Java": "java", + "Ruby": "ruby", + "Haskell": "haskell", + "C#": "c_sharp", + "Swift": "swift", + "Kotlin": "kotlin", + "Scala": "scala", + "PHP": "php", + "Lua": "lua", + "R": "r", + "Julia": "julia", + "Elixir": "elixir", + "Erlang": "erlang", + "OCaml": "ocaml", + "Zig": "zig", + "Bash": "bash", + "CSS": "css", + "HTML": "html", + "SQL": "sql", + "TOML": "toml", + "YAML": "yaml", + "JSON": "json", +} + +# AST node types that represent meaningful code units +CHUNK_NODE_TYPES = { + "function_definition", + "function_declaration", + "method_definition", + "method_declaration", + "class_definition", + "class_declaration", + "struct_definition", + "struct_declaration", + "enum_definition", + "enum_declaration", + "interface_declaration", + "trait_item", + "impl_item", + "module_declaration", + "function_item", + "const_item", + "static_item", + "type_alias", + "type_declaration", + # Go + "function_declaration", + "method_declaration", + "type_declaration", + # Haskell + "function", + "signature", + # Ruby + "method", + "class", + "module", + # JavaScript/TypeScript + "arrow_function", + "generator_function", + "generator_function_declaration", + "export_statement", + "lexical_declaration", +} + + +@dataclass +class CodeChunk: + """A semantic code chunk extracted from a source file.""" + text: str + start_line: int + end_line: int + ast_type: str + name: str + + +class TreeSitterChunker: + """Chunks source code using tree-sitter AST parsing.""" + + def __init__(self): + self._parsers: dict[str, object] = {} + self._available: set[str] | None = None + + def supports(self, language: str) -> bool: + """Check if tree-sitter supports this language.""" + return language in _LANG_TO_TS and self._try_get_language(language) is not None + + def supported_languages(self) -> list[str]: + """Return list of languages with available tree-sitter grammars.""" + if self._available is None: + self._available = set() + for lang in _LANG_TO_TS: + if self._try_get_language(lang) is not None: + self._available.add(lang) + return sorted(self._available) + + def chunk(self, source: str, language: str, min_lines: int = 5, max_lines: int = 100) -> list[CodeChunk]: + """Parse source code and extract semantic chunks. + + Args: + source: Source code text. + language: Language name (e.g. "Python"). + min_lines: Minimum chunk size in lines. + max_lines: Maximum chunk size in lines (large functions get split). + + Returns: + List of CodeChunk objects. + """ + parser = self._get_parser(language) + if parser is None: + return [] + + import tree_sitter + tree = parser.parse(source.encode("utf-8")) + chunks = [] + self._extract_chunks(tree.root_node, source, chunks, min_lines, max_lines) + + # If no semantic chunks found, return the whole file as one chunk + if not chunks and source.strip(): + lines = source.split("\n") + chunks.append(CodeChunk( + text=source, + start_line=1, + end_line=len(lines), + ast_type="file", + name="", + )) + + return chunks + + def _extract_chunks(self, node, source: str, chunks: list[CodeChunk], + min_lines: int, max_lines: int): + """Recursively extract code chunks from AST nodes.""" + # Skip root-level nodes (e.g. Python's 'module', Ruby's 'program') + is_root = node.parent is None + if not is_root and node.type in CHUNK_NODE_TYPES: + start_line = node.start_point[0] + 1 # 1-indexed + end_line = node.end_point[0] + 1 + num_lines = end_line - start_line + 1 + + if num_lines >= min_lines: + text = source[node.start_byte:node.end_byte] + name = self._extract_name(node) + + if num_lines <= max_lines: + chunks.append(CodeChunk( + text=text, + start_line=start_line, + end_line=end_line, + ast_type=node.type, + name=name, + )) + else: + # Split large chunks - first try to extract children + child_chunks = [] + for child in node.children: + self._extract_chunks(child, source, child_chunks, min_lines, max_lines) + + if child_chunks: + chunks.extend(child_chunks) + else: + # Can't split further, include the whole thing + chunks.append(CodeChunk( + text=text, + start_line=start_line, + end_line=end_line, + ast_type=node.type, + name=name, + )) + return # Don't recurse into already-extracted nodes + + # Recurse into children + for child in node.children: + self._extract_chunks(child, source, chunks, min_lines, max_lines) + + def _extract_name(self, node) -> str: + """Extract the name of a function/class/etc from its AST node.""" + for child in node.children: + if child.type in ("identifier", "name", "property_identifier", + "type_identifier", "field_identifier"): + return child.text.decode("utf-8") if isinstance(child.text, bytes) else child.text + return "" + + def _get_parser(self, language: str): + """Get or create a tree-sitter parser for a language.""" + if language in self._parsers: + return self._parsers[language] + + ts_lang = self._try_get_language(language) + if ts_lang is None: + return None + + import tree_sitter + parser = tree_sitter.Parser(ts_lang) + self._parsers[language] = parser + return parser + + def _try_get_language(self, language: str): + """Try to load a tree-sitter language grammar.""" + ts_name = _LANG_TO_TS.get(language) + if ts_name is None: + return None + + try: + import tree_sitter + mod = __import__(f"tree_sitter_{ts_name}") + capsule = mod.language() + # tree-sitter >= 0.23 returns PyCapsule, wrap with Language() + if not isinstance(capsule, tree_sitter.Language): + capsule = tree_sitter.Language(capsule) + return capsule + except (ImportError, AttributeError, TypeError): + return None diff --git a/@ether/library/Index/models/__init__.py b/@ether/library/Index/models/__init__.py new file mode 100644 index 00000000..474a383e --- /dev/null +++ b/@ether/library/Index/models/__init__.py @@ -0,0 +1,10 @@ +"""Model implementations and registry.""" +from .registry import ModelRegistry, register_model_type +from .sentence_transformer import SentenceTransformerModel +from .nomic_bert import NomicBertModel +from .llama_embed import LlamaEmbedModel + +# Register built-in model types +register_model_type("sentence_transformer", SentenceTransformerModel) +register_model_type("nomic_bert", NomicBertModel) +register_model_type("llama", LlamaEmbedModel) diff --git a/@ether/library/Index/models/base.py b/@ether/library/Index/models/base.py new file mode 100644 index 00000000..7e2c3067 --- /dev/null +++ b/@ether/library/Index/models/base.py @@ -0,0 +1,36 @@ +"""Abstract base for embedding models.""" +from __future__ import annotations + +from typing import Protocol, runtime_checkable + +import numpy as np + + +@runtime_checkable +class EmbeddingModel(Protocol): + """Protocol that all embedding models must implement.""" + + @property + def dim(self) -> int: + """Embedding dimensionality.""" + ... + + @property + def max_seq_len(self) -> int: + """Maximum input sequence length.""" + ... + + def embed(self, texts: list[str]) -> np.ndarray: + """Embed a batch of texts into vectors. + + Args: + texts: List of text strings to embed. + + Returns: + numpy array of shape (len(texts), dim), dtype float32. + """ + ... + + def load_weights(self, path: str) -> None: + """Load model weights from the given path.""" + ... diff --git a/@ether/library/Index/models/embedder.py b/@ether/library/Index/models/embedder.py new file mode 100644 index 00000000..8861de85 --- /dev/null +++ b/@ether/library/Index/models/embedder.py @@ -0,0 +1,89 @@ +"""Batch embedding pipeline: text -> vectors. + +Handles batching, progress reporting, and model management. +""" +from __future__ import annotations + +import time +from typing import Callable + +import numpy as np + +from .base import EmbeddingModel +from ..config import DEFAULT_BATCH_SIZE + + +class CodeEmbedder: + """Batch embedding pipeline that processes texts through a model.""" + + def __init__(self, model: EmbeddingModel, batch_size: int = DEFAULT_BATCH_SIZE): + self.model = model + self.batch_size = batch_size + + @property + def dim(self) -> int: + return self.model.dim + + def embed_batch(self, texts: list[str]) -> np.ndarray: + """Embed a single batch of texts.""" + if not texts: + return np.empty((0, self.model.dim), dtype=np.float32) + return self.model.embed(texts) + + def embed_all( + self, + texts: list[str], + progress_callback: Callable[[int, int], None] | None = None, + ) -> np.ndarray: + """Embed all texts in batches, with optional progress reporting. + + Args: + texts: All texts to embed. + progress_callback: Called with (processed_count, total_count) after each batch. + + Returns: + numpy array of shape (len(texts), dim), dtype float32. + """ + if not texts: + return np.empty((0, self.model.dim), dtype=np.float32) + + all_embeddings = [] + total = len(texts) + t0 = time.time() + + for i in range(0, total, self.batch_size): + batch = texts[i : i + self.batch_size] + embeddings = self.embed_batch(batch) + all_embeddings.append(embeddings) + done = min(i + len(batch), total) + if progress_callback: + progress_callback(done, total) + # Print ETA after first batch + if i == 0 and total > self.batch_size: + elapsed = time.time() - t0 + eta_sec = elapsed * (total / len(batch) - 1) + if eta_sec > 60: + print(f" (ETA: {eta_sec/60:.0f}m)", flush=True) + else: + print(f" (ETA: {eta_sec:.0f}s)", flush=True) + + return np.concatenate(all_embeddings, axis=0) + + def embed_with_ids( + self, + items: list[tuple[str, str]], + progress_callback: Callable[[int, int], None] | None = None, + ) -> list[tuple[str, np.ndarray]]: + """Embed items that have (id, text) pairs. + + Returns: + List of (id, embedding_vector) tuples. + """ + if not items: + return [] + + ids = [item[0] for item in items] + texts = [item[1] for item in items] + embeddings = self.embed_all(texts, progress_callback) + + return list(zip(ids, embeddings)) diff --git a/@ether/library/Index/models/llama_embed.py b/@ether/library/Index/models/llama_embed.py new file mode 100644 index 00000000..35a2ddb1 --- /dev/null +++ b/@ether/library/Index/models/llama_embed.py @@ -0,0 +1,125 @@ +"""LLaMA embedding extraction via mean pooling of hidden states. + +Wraps tinygrad's existing LLaMA implementation. +""" +from __future__ import annotations + +import sys +from pathlib import Path + +import numpy as np + +from .base import EmbeddingModel +from ..config import TINYGRAD_DIR + + +class LlamaEmbedModel: + """EmbeddingModel that extracts embeddings from LLaMA via mean pooling.""" + + def __init__(self, config: dict): + self._config = config + self._model = None + self._dim = config.get("hidden_size", 4096) + self._max_seq = config.get("max_position_embeddings", 4096) + + @property + def dim(self) -> int: + return self._dim + + @property + def max_seq_len(self) -> int: + return self._max_seq + + def load_weights(self, path: str) -> None: + """Load LLaMA weights. + + Uses tinygrad's existing LLaMA Transformer class. + Expects the model path to contain safetensors or .pt files. + """ + if not path: + return + + # Add tinygrad extra models to path so we can import it + extra_models = str(TINYGRAD_DIR / "extra" / "models") + if extra_models not in sys.path: + sys.path.insert(0, str(TINYGRAD_DIR)) + sys.path.insert(0, extra_models) + + from tinygrad import Tensor, nn + from tinygrad.nn.state import safe_load, load_state_dict + + # Import LLaMA from tinygrad + from extra.models.llama import Transformer + + cfg = self._config + self._model = Transformer( + dim=cfg.get("hidden_size", 4096), + hidden_dim=cfg.get("intermediate_size", 11008), + n_heads=cfg.get("num_attention_heads", 32), + n_layers=cfg.get("num_hidden_layers", 32), + norm_eps=cfg.get("norm_eps", 1e-5), + vocab_size=cfg.get("vocab_size", 32000), + max_context=cfg.get("max_position_embeddings", 4096), + jit=False, + disable_kv_cache=True, + ) + + model_path = Path(path) + if not model_path.exists(): + print(f"Warning: Model path {path} does not exist.") + return + + state_dict = {} + for sf in sorted(model_path.glob("*.safetensors")): + state_dict.update(safe_load(str(sf))) + if state_dict: + load_state_dict(self._model, state_dict, strict=False) + + def embed(self, texts: list[str]) -> np.ndarray: + """Embed texts using LLaMA hidden states with mean pooling. + + Uses temperature=NaN to get logits, but we intercept at the hidden layer. + """ + if self._model is None: + raise RuntimeError("Model not loaded. Call load_weights() first.") + + import math + from tinygrad import Tensor + + results = [] + for text in texts: + # Simple byte-level tokenization fallback + # In production, use the proper LLaMA tokenizer (sentencepiece) + tokens = self._tokenize(text) + input_ids = Tensor([tokens]) + + # Get hidden states by running through embeddings + layers + norm + h = self._model.tok_embeddings(input_ids) + seq_len = h.shape[1] + freqs_cis = self._model.freqs_cis.cast(h.dtype)[:, :seq_len, :, :, :] + + mask = Tensor.full( + (1, 1, seq_len, seq_len), float("-inf"), dtype=h.dtype + ).triu(1) if seq_len > 1 else None + + for layer in self._model.layers: + h = layer(h, 0, freqs_cis, mask) + h = self._model.norm(h) + + # Mean pool over sequence + embedding = h.mean(axis=1).squeeze(0) + + # L2 normalize + norm = (embedding * embedding).sum().sqrt() + embedding = embedding / norm.maximum(1e-12) + + results.append(embedding.numpy()) + + return np.stack(results) + + def _tokenize(self, text: str) -> list[int]: + """Basic tokenization. In production, use sentencepiece.""" + # Truncate to max_seq_len tokens + # This is a placeholder - real usage needs proper LLaMA tokenizer + encoded = text.encode("utf-8")[:self._max_seq] + return list(encoded) diff --git a/@ether/library/Index/models/nomic_bert.py b/@ether/library/Index/models/nomic_bert.py new file mode 100644 index 00000000..2c93d153 --- /dev/null +++ b/@ether/library/Index/models/nomic_bert.py @@ -0,0 +1,376 @@ +"""NomicBERT implementation in tinygrad. + +Adapts tinygrad's BERT to NomicBERT architecture: +- Rotary Position Embeddings (RoPE) instead of absolute position embeddings +- SwiGLU activation instead of GELU +- No QKV bias +- CLS token pooling + L2 normalization +- 8192 max context, 30528 vocab size + +Supports both CodeRankEmbed (137M, 12 layers) and Nomic Embed Code (7B, 32 layers). +""" +from __future__ import annotations + +import math +from pathlib import Path + +import numpy as np + +from .base import EmbeddingModel + +# Lazy import tinygrad to avoid import errors when not installed +_tinygrad = None +def _get_tinygrad(): + global _tinygrad + if _tinygrad is None: + import tinygrad + _tinygrad = tinygrad + return _tinygrad + + +def precompute_freqs_cis(dim: int, end: int, theta: float = 1000.0): + """Precompute rotary position embedding frequencies.""" + tg = _get_tinygrad() + Tensor = tg.Tensor + freqs = 1.0 / (theta ** (Tensor.arange(0, dim, 2)[:(dim // 2)] / dim)) + freqs = Tensor.arange(end).unsqueeze(dim=1) * freqs.unsqueeze(dim=0) + # Return cos, sin components + return freqs.cos(), freqs.sin() + + +def apply_rotary_emb(x, cos, sin): + """Apply rotary embeddings (GPT-NeoX style, non-interleaved). + + Pairs dimensions (i, i + rotary_dim//2) — first-half/second-half split. + x shape: (batch, seq, heads, head_dim) + cos/sin shape: (seq, rotary_dim//2) + """ + batch, seq, heads, head_dim = x.shape + rotary_dim = cos.shape[-1] * 2 + + # Split into rotary and passthrough parts + x_rot = x[..., :rotary_dim] + x_pass = x[..., rotary_dim:] + + # GPT-NeoX style: split into first half and second half + half = rotary_dim // 2 + x1 = x_rot[..., :half] # first half + x2 = x_rot[..., half:] # second half + + # Reshape cos/sin for broadcasting: (1, seq, 1, rotary_dim//2) + cos = cos[:seq].reshape(1, seq, 1, -1) + sin = sin[:seq].reshape(1, seq, 1, -1) + + # Apply rotation: pairs are (x1[i], x2[i]) sharing frequency i + out1 = x1 * cos - x2 * sin + out2 = x2 * cos + x1 * sin + + # Concatenate halves back + out_rot = out1.cat(out2, dim=-1) + + # Concatenate with passthrough + if x_pass.shape[-1] > 0: + return out_rot.cat(x_pass, dim=-1) + return out_rot + + +class NomicBertEmbeddings: + """Token embeddings only (no position embeddings - RoPE is used instead).""" + + def __init__(self, vocab_size: int, hidden_size: int, type_vocab_size: int = 2): + tg = _get_tinygrad() + nn = tg.nn + self.word_embeddings = nn.Embedding(vocab_size, hidden_size) + self.token_type_embeddings = nn.Embedding(type_vocab_size, hidden_size) + self.norm = nn.LayerNorm(hidden_size, eps=1e-12) + + def __call__(self, input_ids, token_type_ids=None): + tg = _get_tinygrad() + Tensor = tg.Tensor + embeddings = self.word_embeddings(input_ids) + # Always add token_type_embeddings (default type 0) — trained bias vector + if token_type_ids is None: + token_type_ids = Tensor.zeros(*input_ids.shape, dtype=tg.dtypes.int) + embeddings = embeddings + self.token_type_embeddings(token_type_ids) + return self.norm(embeddings) + + +class NomicBertSelfAttention: + """Multi-head self-attention with Rotary Position Embeddings.""" + + def __init__(self, hidden_size: int, num_attention_heads: int, rotary_emb_fraction: float = 0.5): + tg = _get_tinygrad() + nn = tg.nn + self.num_heads = num_attention_heads + self.head_dim = hidden_size // num_attention_heads + self.rotary_dim = int(self.head_dim * rotary_emb_fraction) + + # No bias in NomicBERT QKV projections + self.Wqkv = nn.Linear(hidden_size, 3 * hidden_size, bias=False) + self.out_proj = nn.Linear(hidden_size, hidden_size, bias=False) + + def __call__(self, hidden_states, cos, sin, attention_mask=None): + tg = _get_tinygrad() + Tensor = tg.Tensor + batch, seq_len, hidden = hidden_states.shape + + # Compute Q, K, V in one projection + qkv = self.Wqkv(hidden_states) + q, k, v = qkv.chunk(3, dim=-1) + + # Reshape to (batch, seq, heads, head_dim) + q = q.reshape(batch, seq_len, self.num_heads, self.head_dim) + k = k.reshape(batch, seq_len, self.num_heads, self.head_dim) + v = v.reshape(batch, seq_len, self.num_heads, self.head_dim) + + # Apply rotary embeddings + q = apply_rotary_emb(q, cos, sin) + k = apply_rotary_emb(k, cos, sin) + + # Transpose for attention: (batch, heads, seq, head_dim) + q = q.transpose(1, 2) + k = k.transpose(1, 2) + v = v.transpose(1, 2) + + # Scaled dot-product attention + attn = Tensor.scaled_dot_product_attention(q, k, v, attention_mask, 0.0) + + # Reshape back + attn = attn.transpose(1, 2).reshape(batch, seq_len, hidden) + return self.out_proj(attn) + + +class NomicBertSwiGLU: + """SwiGLU feed-forward: fc2(fc11(x) * silu(fc12(x)))""" + + def __init__(self, hidden_size: int, intermediate_size: int): + tg = _get_tinygrad() + nn = tg.nn + self.fc11 = nn.Linear(hidden_size, intermediate_size, bias=False) + self.fc12 = nn.Linear(hidden_size, intermediate_size, bias=False) + self.fc2 = nn.Linear(intermediate_size, hidden_size, bias=False) + + def __call__(self, x): + # fc12 is the gate (gets silu), fc11 is the up projection + return self.fc2(self.fc11(x) * self.fc12(x).silu()) + + +class NomicBertLayer: + """Single transformer layer with RoPE attention + SwiGLU.""" + + def __init__(self, hidden_size: int, intermediate_size: int, + num_attention_heads: int, rotary_emb_fraction: float): + tg = _get_tinygrad() + nn = tg.nn + self.attn = NomicBertSelfAttention(hidden_size, num_attention_heads, rotary_emb_fraction) + self.mlp = NomicBertSwiGLU(hidden_size, intermediate_size) + self.norm1 = nn.LayerNorm(hidden_size, eps=1e-12) + self.norm2 = nn.LayerNorm(hidden_size, eps=1e-12) + + def __call__(self, hidden_states, cos, sin, attention_mask=None): + # Post-norm: attention then norm (prenorm=false in model config) + residual = hidden_states + hidden_states = self.attn(hidden_states, cos, sin, attention_mask) + hidden_states = self.norm1(residual + hidden_states) + + # Post-norm: FFN then norm + residual = hidden_states + hidden_states = self.mlp(hidden_states) + hidden_states = self.norm2(residual + hidden_states) + + return hidden_states + + +class NomicBertEncoder: + """Stack of NomicBERT transformer layers.""" + + def __init__(self, hidden_size: int, intermediate_size: int, + num_attention_heads: int, num_hidden_layers: int, + rotary_emb_fraction: float): + self.layers = [ + NomicBertLayer(hidden_size, intermediate_size, num_attention_heads, rotary_emb_fraction) + for _ in range(num_hidden_layers) + ] + + def __call__(self, hidden_states, cos, sin, attention_mask=None): + for layer in self.layers: + hidden_states = layer(hidden_states, cos, sin, attention_mask) + return hidden_states + + +class NomicBert: + """NomicBERT model: embeddings + encoder + CLS pooling + L2 norm.""" + + def __init__(self, vocab_size: int = 30528, hidden_size: int = 768, + intermediate_size: int = 3072, num_attention_heads: int = 12, + num_hidden_layers: int = 12, max_position_embeddings: int = 8192, + type_vocab_size: int = 2, rotary_emb_fraction: float = 1.0, + rotary_emb_base: float = 1000.0): + self.hidden_size = hidden_size + self.max_position_embeddings = max_position_embeddings + + self.embeddings = NomicBertEmbeddings(vocab_size, hidden_size, type_vocab_size) + self.encoder = NomicBertEncoder( + hidden_size, intermediate_size, num_attention_heads, + num_hidden_layers, rotary_emb_fraction, + ) + + head_dim = hidden_size // num_attention_heads + rotary_dim = int(head_dim * rotary_emb_fraction) + self.cos, self.sin = precompute_freqs_cis(rotary_dim, max_position_embeddings, rotary_emb_base) + + def __call__(self, input_ids, attention_mask=None, token_type_ids=None): + tg = _get_tinygrad() + Tensor = tg.Tensor + + hidden_states = self.embeddings(input_ids, token_type_ids) + + # Build causal-free attention mask + attn_mask = None + if attention_mask is not None: + # (batch, seq) -> (batch, 1, 1, seq) for broadcasting + attn_mask = attention_mask.unsqueeze(1).unsqueeze(2) + attn_mask = (1.0 - attn_mask) * -10000.0 + + hidden_states = self.encoder(hidden_states, self.cos, self.sin, attn_mask) + + # CLS token pooling (first token) + cls_output = hidden_states[:, 0] + + # L2 normalization in float32 + norm = (cls_output * cls_output).sum(axis=-1, keepdim=True).sqrt() + cls_output = cls_output / norm.maximum(1e-12) + + return cls_output + + +class NomicBertModel: + """EmbeddingModel implementation for NomicBERT (CodeRankEmbed / Nomic Embed Code).""" + + def __init__(self, config: dict): + self._config = config + self._model: NomicBert | None = None + self._dim = config.get("hidden_size", 768) + self._max_seq = config.get("max_position_embeddings", 8192) + self._query_prefix = config.get("query_prefix", "search_query: ") + self._document_prefix = config.get("document_prefix", "search_document: ") + self._mode = "document" + + @property + def dim(self) -> int: + return self._dim + + @property + def max_seq_len(self) -> int: + return self._max_seq + + def set_mode(self, mode: str): + """Set embedding mode: 'query' or 'document'.""" + if mode not in ("query", "document"): + raise ValueError(f"mode must be 'query' or 'document', got '{mode}'") + self._mode = mode + + def load_weights(self, path: str) -> None: + """Load NomicBERT weights from safetensors files.""" + tg = _get_tinygrad() + from tinygrad import Device + from tinygrad.nn.state import safe_load, load_state_dict + + # Use GPU if available + try: + Device.DEFAULT = 'CL' + print(f" Using device: {Device.DEFAULT}", flush=True) + except Exception: + print(f" Using device: {Device.DEFAULT} (no GPU found)", flush=True) + + cfg = self._config + self._model = NomicBert( + vocab_size=cfg.get("vocab_size", 30528), + hidden_size=cfg.get("hidden_size", 768), + intermediate_size=cfg.get("intermediate_size", 3072), + num_attention_heads=cfg.get("num_attention_heads", 12), + num_hidden_layers=cfg.get("num_hidden_layers", 12), + max_position_embeddings=cfg.get("max_position_embeddings", 8192), + rotary_emb_fraction=cfg.get("rotary_emb_fraction", 1.0), + rotary_emb_base=cfg.get("rotary_emb_base", 1000.0), + ) + + if not path: + return + + model_path = Path(path) + if not model_path.exists(): + print(f"Warning: Model path {path} does not exist. Model initialized with random weights.") + return + + # Load safetensors files + safetensor_files = sorted(model_path.glob("*.safetensors")) + if not safetensor_files: + print(f"Warning: No safetensors files found in {path}") + return + + state_dict = {} + for sf in safetensor_files: + state_dict.update(safe_load(str(sf))) + + # Map HuggingFace weight names to our model structure + mapped = _map_hf_weights(state_dict) + load_state_dict(self._model, mapped, strict=False) + + + def _ensure_tokenizer(self): + if not hasattr(self, '_tokenizer'): + from .tokenizer import WordPieceTokenizer + model_path = Path(self._config.get("path", "")) + vocab_path = model_path / "vocab.txt" + if not vocab_path.exists(): + raise FileNotFoundError(f"vocab.txt not found at {vocab_path}") + self._tokenizer = WordPieceTokenizer(str(vocab_path), max_length=min(self._max_seq, 512)) + + def tokenize(self, texts: list[str]) -> tuple: + """Pre-tokenize texts (CPU). Returns (ids, masks) numpy arrays.""" + self._ensure_tokenizer() + prefix = self._query_prefix if self._mode == "query" else self._document_prefix + prefixed = [prefix + t for t in texts] + return self._tokenizer.batch_encode(prefixed) + + def embed_tokenized(self, all_ids, all_masks) -> np.ndarray: + """Embed pre-tokenized inputs (GPU).""" + tg = _get_tinygrad() + Tensor = tg.Tensor + input_ids = Tensor(all_ids) + attention_mask = Tensor(all_masks) + embeddings = self._model(input_ids, attention_mask) + return embeddings.numpy() + + def embed(self, texts: list[str]) -> np.ndarray: + """Embed texts using NomicBERT with appropriate prefix based on mode.""" + if self._model is None: + raise RuntimeError("Model not loaded. Call load_weights() first.") + all_ids, all_masks = self.tokenize(texts) + return self.embed_tokenized(all_ids, all_masks) + + +def _map_hf_weights(state_dict: dict) -> dict: + """Map HuggingFace NomicBERT weight names to our model structure. + + HF weight names -> Our model structure: + emb_ln.{weight,bias} -> embeddings.norm.{weight,bias} + embeddings.word_embeddings.weight -> embeddings.word_embeddings.weight + embeddings.token_type_embeddings.weight -> embeddings.token_type_embeddings.weight + encoder.layers.N.attn.Wqkv.weight -> encoder.layers.N.attn.Wqkv.weight + encoder.layers.N.attn.out_proj.weight -> encoder.layers.N.attn.out_proj.weight + encoder.layers.N.mlp.fc11.weight -> encoder.layers.N.mlp.fc11.weight + encoder.layers.N.mlp.fc12.weight -> encoder.layers.N.mlp.fc12.weight + encoder.layers.N.mlp.fc2.weight -> encoder.layers.N.mlp.fc2.weight + encoder.layers.N.norm1.{weight,bias} -> encoder.layers.N.norm1.{weight,bias} + encoder.layers.N.norm2.{weight,bias} -> encoder.layers.N.norm2.{weight,bias} + """ + mapped = {} + for k, v in state_dict.items(): + new_key = k + # emb_ln -> embeddings.norm + new_key = new_key.replace("emb_ln.", "embeddings.norm.") + # Everything else matches our structure directly + mapped[new_key] = v + return mapped diff --git a/@ether/library/Index/models/registry.py b/@ether/library/Index/models/registry.py new file mode 100644 index 00000000..f11f605c --- /dev/null +++ b/@ether/library/Index/models/registry.py @@ -0,0 +1,91 @@ +"""Model registry: register, load, and switch models by name.""" +from __future__ import annotations + +from typing import Any + +from ..config import load_models_config, save_models_config +from .base import EmbeddingModel + + +# Map from model type string to model class +_MODEL_TYPES: dict[str, type] = {} + + +def register_model_type(type_name: str, cls: type): + """Register a model class for a type name (e.g. 'nomic_bert').""" + _MODEL_TYPES[type_name] = cls + + +class ModelRegistry: + """Manages loading and switching between embedding models.""" + + def __init__(self): + self._loaded: dict[str, EmbeddingModel] = {} + self._config = load_models_config() + + @property + def config(self) -> dict: + return self._config + + @property + def indexing_model_name(self) -> str: + return self._config["indexing"] + + @property + def reranking_model_name(self) -> str: + return self._config["reranking"] + + def list_models(self) -> dict[str, dict]: + """List all registered models with their config.""" + return self._config.get("models", {}) + + def get_model_config(self, name: str) -> dict: + """Get config for a specific model.""" + models = self._config.get("models", {}) + if name not in models: + raise KeyError(f"Unknown model: {name}. Available: {list(models.keys())}") + return models[name] + + def load(self, name: str) -> EmbeddingModel: + """Load a model by name (cached after first load).""" + if name in self._loaded: + return self._loaded[name] + + cfg = self.get_model_config(name) + model_type = cfg["type"] + if model_type not in _MODEL_TYPES: + raise ValueError( + f"Unknown model type '{model_type}'. " + f"Registered types: {list(_MODEL_TYPES.keys())}" + ) + + cls = _MODEL_TYPES[model_type] + model = cls(cfg) + model.load_weights(cfg.get("path", "")) + self._loaded[name] = model + return model + + def get_indexing_model(self) -> EmbeddingModel: + """Load and return the current indexing model.""" + return self.load(self.indexing_model_name) + + def get_reranking_model(self) -> EmbeddingModel: + """Load and return the current reranking model.""" + return self.load(self.reranking_model_name) + + def select(self, name: str, task: str): + """Switch the active model for a task ('indexing' or 'reranking').""" + if task not in ("indexing", "reranking"): + raise ValueError(f"task must be 'indexing' or 'reranking', got '{task}'") + # Verify the model exists + self.get_model_config(name) + self._config[task] = name + save_models_config(self._config) + + def unload(self, name: str): + """Unload a model from memory.""" + self._loaded.pop(name, None) + + def unload_all(self): + """Unload all models from memory.""" + self._loaded.clear() diff --git a/@ether/library/Index/models/sentence_transformer.py b/@ether/library/Index/models/sentence_transformer.py new file mode 100644 index 00000000..4d53d532 --- /dev/null +++ b/@ether/library/Index/models/sentence_transformer.py @@ -0,0 +1,139 @@ +"""HuggingFace transformers wrapper for embedding models. + +Uses transformers + torch directly for fast local loading. +Supports CodeRankEmbed and other NomicBERT-based models. +""" +from __future__ import annotations + +import numpy as np + +from .base import EmbeddingModel + + +class SentenceTransformerModel: + """EmbeddingModel using HuggingFace transformers with local-first loading.""" + + def __init__(self, config: dict): + self._config = config + self._model = None + self._tokenizer = None + self._dim = config.get("hidden_size", 768) + self._max_seq = config.get("max_position_embeddings", 8192) + self._model_name = config.get("hf_name", "") + self._query_prefix = config.get("query_prefix", "search_query: ") + self._document_prefix = config.get("document_prefix", "search_document: ") + self._mode = "document" # default to document embedding + self._pooling = config.get("pooling", "cls") # "cls" or "last_token" + + @property + def dim(self) -> int: + return self._dim + + @property + def max_seq_len(self) -> int: + return self._max_seq + + def set_mode(self, mode: str): + """Set embedding mode: 'query' or 'document'.""" + if mode not in ("query", "document"): + raise ValueError(f"mode must be 'query' or 'document', got '{mode}'") + self._mode = mode + + def load_weights(self, path: str) -> None: + """Load model, preferring local cache to avoid network calls.""" + import logging + logging.getLogger("transformers").setLevel(logging.ERROR) + + import torch + import transformers + transformers.logging.set_verbosity_error() + # Suppress the "custom code" interactive prompt for local model files + transformers.dynamic_module_utils.resolve_trust_remote_code = lambda *a, **kw: True + from transformers import AutoTokenizer, AutoModel + + model_id = self._model_name or path + if not model_id: + raise ValueError("No model name or path specified") + + # Use float16 for large models (>1B params) to save memory + size_str = self._config.get("size", "") + use_fp16 = any(s in size_str for s in ("B", "b")) and "M" not in size_str + dtype_kwargs = {"torch_dtype": torch.float16} if use_fp16 else {} + if use_fp16: + print(f" Loading {model_id} in float16 to save memory", flush=True) + + # Try local snapshot first for fast offline loading + local_path = _find_local_snapshot(model_id) + if local_path: + self._tokenizer = AutoTokenizer.from_pretrained(local_path) + self._model = AutoModel.from_pretrained( + local_path, trust_remote_code=True, local_files_only=True, + **dtype_kwargs, + ) + else: + # Fall back to downloading + print(f" Downloading {model_id}...", flush=True) + self._tokenizer = AutoTokenizer.from_pretrained(model_id) + self._model = AutoModel.from_pretrained( + model_id, trust_remote_code=True, + **dtype_kwargs, + ) + + self._model.eval() + self._dim = self._model.config.hidden_size + + def embed(self, texts: list[str]) -> np.ndarray: + """Embed texts with appropriate prefix based on mode.""" + if self._model is None: + raise RuntimeError("Model not loaded. Call load_weights() first.") + + import torch + import torch.nn.functional as F + + prefix = self._query_prefix if self._mode == "query" else self._document_prefix + prefixed = [prefix + t for t in texts] + + # Cap at 512 tokens for code chunks (keeps memory reasonable) + max_len = min(self._max_seq, 512) + inputs = self._tokenizer( + prefixed, return_tensors="pt", padding=True, + truncation=True, max_length=max_len, + ) + + with torch.no_grad(): + outputs = self._model(**inputs) + + # Pooling + L2 normalize + if self._pooling == "last_token": + # Last non-padding token pooling (for Qwen/decoder models) + seq_lens = inputs["attention_mask"].sum(dim=1) - 1 + embeddings = outputs.last_hidden_state[torch.arange(len(texts)), seq_lens] + else: + # CLS pooling (first token) + embeddings = outputs.last_hidden_state[:, 0] + embeddings = F.normalize(embeddings.float(), p=2, dim=1) + return embeddings.numpy() + + +def _find_local_snapshot(model_id: str) -> str | None: + """Find the local HuggingFace cache snapshot for a model.""" + from pathlib import Path + + cache_dir = Path.home() / ".cache" / "huggingface" / "hub" + # HF cache uses -- as separator: "nomic-ai/CodeRankEmbed" -> "models--nomic-ai--CodeRankEmbed" + dir_name = "models--" + model_id.replace("/", "--") + model_dir = cache_dir / dir_name / "snapshots" + + if not model_dir.exists(): + return None + + # Get the most recent snapshot + snapshots = sorted(model_dir.iterdir(), key=lambda p: p.stat().st_mtime, reverse=True) + if not snapshots: + return None + + snapshot = snapshots[0] + # Verify it has the essential files + if (snapshot / "config.json").exists(): + return str(snapshot) + return None diff --git a/@ether/library/Index/models/tokenizer.py b/@ether/library/Index/models/tokenizer.py new file mode 100644 index 00000000..9ed13905 --- /dev/null +++ b/@ether/library/Index/models/tokenizer.py @@ -0,0 +1,177 @@ +"""WordPiece tokenizer (pure Python, from vocab.txt). + +Compatible with BERT/NomicBERT tokenization. +""" +from __future__ import annotations + +import re +import unicodedata +from pathlib import Path + +# Special tokens +PAD_TOKEN = "[PAD]" +UNK_TOKEN = "[UNK]" +CLS_TOKEN = "[CLS]" +SEP_TOKEN = "[SEP]" + + +class WordPieceTokenizer: + """Pure Python WordPiece tokenizer that reads vocab.txt.""" + + def __init__(self, vocab_path: str, max_length: int = 8192): + self.max_length = max_length + self.vocab: dict[str, int] = {} + self.inv_vocab: dict[int, str] = {} + + with open(vocab_path) as f: + for idx, line in enumerate(f): + token = line.rstrip("\n") + self.vocab[token] = idx + self.inv_vocab[idx] = token + + self.pad_id = self.vocab.get(PAD_TOKEN, 0) + self.unk_id = self.vocab.get(UNK_TOKEN, 100) + self.cls_id = self.vocab.get(CLS_TOKEN, 101) + self.sep_id = self.vocab.get(SEP_TOKEN, 102) + + def tokenize(self, text: str) -> list[str]: + """Tokenize text into WordPiece tokens.""" + tokens = [] + for word in self._basic_tokenize(text): + sub_tokens = self._wordpiece_tokenize(word) + tokens.extend(sub_tokens) + return tokens + + def encode(self, text: str) -> tuple[list[int], list[int]]: + """Encode text to token IDs and attention mask (unpadded). + + Returns: + (input_ids, attention_mask) - truncated to max_length but NOT padded. + """ + tokens = self.tokenize(text) + # Truncate to max_length - 2 (for CLS and SEP) + max_tokens = self.max_length - 2 + tokens = tokens[:max_tokens] + + # Build input_ids: [CLS] + tokens + [SEP] + input_ids = [self.cls_id] + for t in tokens: + input_ids.append(self.vocab.get(t, self.unk_id)) + input_ids.append(self.sep_id) + + # Build attention mask + attention_mask = [1] * len(input_ids) + + return input_ids, attention_mask + + def batch_encode(self, texts: list[str]) -> tuple[list[list[int]], list[list[int]]]: + """Encode a batch of texts, padding to the max length in the batch. + + Returns: + (all_input_ids, all_attention_masks) - padded to batch max length. + """ + encoded = [self.encode(text) for text in texts] + # Pad to the longest sequence in this batch (not global max_length) + max_len = max(len(ids) for ids, _ in encoded) if encoded else 0 + all_ids = [] + all_masks = [] + for ids, mask in encoded: + pad_len = max_len - len(ids) + all_ids.append(ids + [self.pad_id] * pad_len) + all_masks.append(mask + [0] * pad_len) + return all_ids, all_masks + + def _basic_tokenize(self, text: str) -> list[str]: + """Basic tokenization: lowercase, strip accents, split on punctuation/whitespace.""" + text = text.lower() + text = self._strip_accents(text) + text = self._tokenize_chinese_chars(text) + + tokens = [] + for word in text.split(): + # Split on punctuation + sub = self._split_on_punctuation(word) + tokens.extend(sub) + return [t for t in tokens if t.strip()] + + def _wordpiece_tokenize(self, word: str) -> list[str]: + """WordPiece tokenization of a single word.""" + if word in self.vocab: + return [word] + + tokens = [] + start = 0 + while start < len(word): + end = len(word) + found = None + while start < end: + substr = word[start:end] + if start > 0: + substr = "##" + substr + if substr in self.vocab: + found = substr + break + end -= 1 + if found is None: + tokens.append(UNK_TOKEN) + break + tokens.append(found) + start = end + return tokens + + @staticmethod + def _strip_accents(text: str) -> str: + output = [] + for char in unicodedata.normalize("NFD", text): + if unicodedata.category(char) == "Mn": + continue + output.append(char) + return "".join(output) + + @staticmethod + def _tokenize_chinese_chars(text: str) -> str: + """Add whitespace around CJK characters.""" + output = [] + for char in text: + cp = ord(char) + if ( + (0x4E00 <= cp <= 0x9FFF) + or (0x3400 <= cp <= 0x4DBF) + or (0x20000 <= cp <= 0x2A6DF) + or (0x2A700 <= cp <= 0x2B73F) + or (0x2B740 <= cp <= 0x2B81F) + or (0x2B820 <= cp <= 0x2CEAF) + or (0xF900 <= cp <= 0xFAFF) + or (0x2F800 <= cp <= 0x2FA1F) + ): + output.append(f" {char} ") + else: + output.append(char) + return "".join(output) + + @staticmethod + def _split_on_punctuation(text: str) -> list[str]: + """Split a word on punctuation characters.""" + tokens = [] + current = [] + for char in text: + if _is_punctuation(char): + if current: + tokens.append("".join(current)) + current = [] + tokens.append(char) + else: + current.append(char) + if current: + tokens.append("".join(current)) + return tokens + + +def _is_punctuation(char: str) -> bool: + """Check if a character is punctuation.""" + cp = ord(char) + # ASCII punctuation + if (33 <= cp <= 47) or (58 <= cp <= 64) or (91 <= cp <= 96) or (123 <= cp <= 126): + return True + cat = unicodedata.category(char) + return cat.startswith("P") diff --git a/@ether/library/Index/query/__init__.py b/@ether/library/Index/query/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/@ether/library/Index/query/cross_lang.py b/@ether/library/Index/query/cross_lang.py new file mode 100644 index 00000000..c24e100c --- /dev/null +++ b/@ether/library/Index/query/cross_lang.py @@ -0,0 +1,141 @@ +"""Cross-language equivalence finder. + +Given code in language X, find equivalent implementations across other languages. +Optionally reranks with a larger model and structural comparison. +""" +from __future__ import annotations + +from ..models.base import EmbeddingModel +from ..store.vector_store import VectorStore +from ..config import DEFAULT_SEARCH_LIMIT, DEFAULT_RERANK_CANDIDATES +from .semantic import SemanticSearch +from .structural import compare +from .results import SearchResult, EquivalenceResult + + +class CrossLanguageFinder: + """Find equivalent implementations across languages.""" + + def __init__( + self, + search_model: EmbeddingModel, + store: VectorStore, + rerank_model: EmbeddingModel | None = None, + ): + self._search = SemanticSearch(search_model, store) + self._rerank_model = rerank_model + self._store = store + + def find_equivalents( + self, + code: str, + source_language: str, + limit: int = DEFAULT_SEARCH_LIMIT, + rerank: bool = True, + structural: bool = True, + target_languages: list[str] | None = None, + ) -> EquivalenceResult: + """Find equivalent implementations in other languages. + + Args: + code: Source code to find equivalents for. + source_language: Language of the source code. + limit: Number of results to return. + rerank: Whether to rerank with the larger model. + structural: Whether to add structural comparison scores. + target_languages: Specific languages to search (None = all). + + Returns: + EquivalenceResult with ranked equivalents. + """ + # Get more candidates than limit for reranking + candidates_limit = DEFAULT_RERANK_CANDIDATES if rerank and self._rerank_model else limit + + # Determine language exclusion + exclude_langs = [source_language] + + if target_languages: + # Search each target language + results: list[SearchResult] = [] + for lang in target_languages: + if lang == source_language: + continue + lang_results = self._search.search( + code, + limit=candidates_limit // max(len(target_languages), 1), + language=lang, + ) + results.extend(lang_results) + else: + results = self._search.search( + code, + limit=candidates_limit, + exclude_languages=exclude_langs, + ) + + # Rerank with larger model + if rerank and self._rerank_model and results: + results = self._rerank(code, results, limit * 2) + + # Add structural scores + if structural and results: + for result in results: + try: + comp = compare(code, source_language, result.text, result.language) + result.structural_score = comp.similarity + except Exception: + pass + + # Sort by combined score (semantic + structural) + results = _combined_sort(results) + + return EquivalenceResult( + source_language=source_language, + source_code=code, + equivalents=results[:limit], + ) + + def _rerank(self, query_code: str, candidates: list[SearchResult], limit: int) -> list[SearchResult]: + """Rerank candidates using the larger model.""" + if not self._rerank_model: + return candidates + + import numpy as np + + # Embed query with reranking model (query mode) + if hasattr(self._rerank_model, 'set_mode'): + self._rerank_model.set_mode('query') + query_vec = self._rerank_model.embed([query_code])[0] + + # Embed all candidate texts (document mode) + if hasattr(self._rerank_model, 'set_mode'): + self._rerank_model.set_mode('document') + texts = [r.text for r in candidates] + candidate_vecs = self._rerank_model.embed(texts) + + # Compute cosine similarity + similarities = candidate_vecs @ query_vec + norms = np.linalg.norm(candidate_vecs, axis=1) * np.linalg.norm(query_vec) + norms = np.maximum(norms, 1e-12) + scores = similarities / norms + + # Update scores and sort + for i, result in enumerate(candidates): + result.score = float(1.0 - scores[i]) # Convert to distance-like score + + candidates.sort(key=lambda r: r.score) + return candidates[:limit] + + +def _combined_sort(results: list[SearchResult]) -> list[SearchResult]: + """Sort results by combined semantic + structural score.""" + def sort_key(r: SearchResult) -> float: + semantic = r.score # Lower is better (distance) + if r.structural_score is not None: + # Structural is 0-1 (higher is better), convert to distance-like + structural = 1.0 - r.structural_score + return 0.7 * semantic + 0.3 * structural + return semantic + + results.sort(key=sort_key) + return results diff --git a/@ether/library/Index/query/results.py b/@ether/library/Index/query/results.py new file mode 100644 index 00000000..d5238b43 --- /dev/null +++ b/@ether/library/Index/query/results.py @@ -0,0 +1,80 @@ +"""Result dataclasses and formatting for search results.""" +from __future__ import annotations + +from dataclasses import dataclass, field + + +@dataclass +class SearchResult: + """A single search result.""" + chunk_id: str + language: str + version: str + file_path: str + repo: str + start_line: int + end_line: int + ast_type: str + name: str + text: str + score: float # Similarity score (lower distance = better) + structural_score: float | None = None + + def to_dict(self) -> dict: + d = { + "chunk_id": self.chunk_id, + "language": self.language, + "version": self.version, + "file_path": self.file_path, + "repo": self.repo, + "start_line": self.start_line, + "end_line": self.end_line, + "ast_type": self.ast_type, + "name": self.name, + "text": self.text, + "score": self.score, + } + if self.structural_score is not None: + d["structural_score"] = self.structural_score + return d + + def summary(self) -> str: + """Short human-readable summary.""" + name_part = f" {self.name}" if self.name else "" + return ( + f"[{self.language}] {self.repo}:{self.file_path}" + f" L{self.start_line}-{self.end_line}" + f" ({self.ast_type}{name_part}) score={self.score:.4f}" + ) + + +@dataclass +class ComparisonResult: + """Result of structural comparison between two code fragments.""" + similarity: float + features_a: dict + features_b: dict + details: dict = field(default_factory=dict) + + def to_dict(self) -> dict: + return { + "similarity": self.similarity, + "features_a": self.features_a, + "features_b": self.features_b, + "details": self.details, + } + + +@dataclass +class EquivalenceResult: + """Result of cross-language equivalence search.""" + source_language: str + source_code: str + equivalents: list[SearchResult] + + def to_dict(self) -> dict: + return { + "source_language": self.source_language, + "source_code": self.source_code[:200] + ("..." if len(self.source_code) > 200 else ""), + "equivalents": [r.to_dict() for r in self.equivalents], + } diff --git a/@ether/library/Index/query/semantic.py b/@ether/library/Index/query/semantic.py new file mode 100644 index 00000000..eb683214 --- /dev/null +++ b/@ether/library/Index/query/semantic.py @@ -0,0 +1,85 @@ +"""Semantic code search via vector similarity.""" +from __future__ import annotations + +import numpy as np + +from ..models.base import EmbeddingModel +from ..store.vector_store import VectorStore +from ..config import DEFAULT_SEARCH_LIMIT +from .results import SearchResult + + +class SemanticSearch: + """Embed query -> vector search -> rank results.""" + + def __init__(self, model: EmbeddingModel, store: VectorStore): + self.model = model + self.store = store + + def search( + self, + query: str, + limit: int = DEFAULT_SEARCH_LIMIT, + language: str | None = None, + version: str | None = None, + ast_type: str | None = None, + repo: str | None = None, + exclude_languages: list[str] | None = None, + ) -> list[SearchResult]: + """Search for code similar to the query text. + + Args: + query: Natural language or code query. + limit: Max results. + language: Filter to language. + version: Filter to version. + ast_type: Filter to AST type. + repo: Filter to repo. + exclude_languages: Languages to exclude. + + Returns: + List of SearchResult objects sorted by similarity. + """ + # Set query mode for models that support it (e.g. sentence-transformers) + if hasattr(self.model, 'set_mode'): + self.model.set_mode('query') + query_vector = self.model.embed([query])[0] + + # Search the store + raw_results = self.store.search( + query_vector=query_vector, + limit=limit, + language=language, + version=version, + ast_type=ast_type, + repo=repo, + exclude_languages=exclude_languages, + ) + + return [_to_search_result(r) for r in raw_results] + + def search_by_code( + self, + code: str, + limit: int = DEFAULT_SEARCH_LIMIT, + **kwargs, + ) -> list[SearchResult]: + """Search using a code snippet as query (same as search, semantic alias).""" + return self.search(code, limit=limit, **kwargs) + + +def _to_search_result(raw: dict) -> SearchResult: + """Convert a raw LanceDB result dict to a SearchResult.""" + return SearchResult( + chunk_id=raw.get("chunk_id", ""), + language=raw.get("language", ""), + version=raw.get("version", ""), + file_path=raw.get("file_path", ""), + repo=raw.get("repo", ""), + start_line=raw.get("start_line", 0), + end_line=raw.get("end_line", 0), + ast_type=raw.get("ast_type", ""), + name=raw.get("name", ""), + text=raw.get("text", ""), + score=raw.get("_distance", 0.0), + ) diff --git a/@ether/library/Index/query/structural.py b/@ether/library/Index/query/structural.py new file mode 100644 index 00000000..8db2ef0a --- /dev/null +++ b/@ether/library/Index/query/structural.py @@ -0,0 +1,203 @@ +"""Tree-sitter AST structural comparison (second pass after semantic search). + +Extracts language-agnostic structural features and computes similarity. +""" +from __future__ import annotations + +import math +from typing import Any + +from .results import ComparisonResult + + +def extract_features(code: str, language: str) -> dict: + """Extract language-agnostic structural features from code. + + Features: + - param_count: Number of parameters (for functions) + - nesting_depth: Maximum nesting depth + - cyclomatic_complexity: Approximation of cyclomatic complexity + - control_flow: Set of control flow patterns used + - line_count: Number of non-empty lines + - has_recursion: Whether function appears to call itself + - has_loop: Whether code contains loops + - has_conditional: Whether code contains conditionals + """ + features: dict[str, Any] = { + "line_count": len([l for l in code.split("\n") if l.strip()]), + "param_count": 0, + "nesting_depth": 0, + "cyclomatic_complexity": 1, + "control_flow": [], + "has_loop": False, + "has_conditional": False, + "has_recursion": False, + } + + try: + from ..indexing.tree_sitter_chunker import TreeSitterChunker, _LANG_TO_TS + chunker = TreeSitterChunker() + if not chunker.supports(language): + return _extract_features_heuristic(code, features) + + import tree_sitter + ts_name = _LANG_TO_TS.get(language) + if ts_name is None: + return _extract_features_heuristic(code, features) + + mod = __import__(f"tree_sitter_{ts_name}") + lang = mod.language() + parser = tree_sitter.Parser(lang) + tree = parser.parse(code.encode("utf-8")) + + _analyze_node(tree.root_node, features, 0) + except (ImportError, Exception): + return _extract_features_heuristic(code, features) + + return features + + +def compare(code_a: str, lang_a: str, code_b: str, lang_b: str) -> ComparisonResult: + """Compare two code fragments structurally. + + Args: + code_a: First code fragment. + lang_a: Language of first fragment. + code_b: Second code fragment. + lang_b: Language of second fragment. + + Returns: + ComparisonResult with similarity score and feature breakdown. + """ + features_a = extract_features(code_a, lang_a) + features_b = extract_features(code_b, lang_b) + + similarity = _compute_similarity(features_a, features_b) + + return ComparisonResult( + similarity=similarity, + features_a=features_a, + features_b=features_b, + details={ + "param_match": features_a["param_count"] == features_b["param_count"], + "depth_diff": abs(features_a["nesting_depth"] - features_b["nesting_depth"]), + "complexity_diff": abs(features_a["cyclomatic_complexity"] - features_b["cyclomatic_complexity"]), + "control_flow_overlap": len( + set(features_a["control_flow"]) & set(features_b["control_flow"]) + ), + }, + ) + + +def _analyze_node(node, features: dict, depth: int): + """Recursively analyze AST nodes to extract features.""" + features["nesting_depth"] = max(features["nesting_depth"], depth) + + node_type = node.type + + # Count parameters + if node_type in ("parameters", "formal_parameters", "parameter_list"): + features["param_count"] = max(features["param_count"], len([ + c for c in node.children + if c.type not in ("(", ")", ",", "comment") + ])) + + # Track control flow + if node_type in ("if_statement", "if_expression", "conditional_expression"): + features["has_conditional"] = True + features["cyclomatic_complexity"] += 1 + if "if" not in features["control_flow"]: + features["control_flow"].append("if") + + elif node_type in ("for_statement", "for_expression", "for_in_statement"): + features["has_loop"] = True + features["cyclomatic_complexity"] += 1 + if "for" not in features["control_flow"]: + features["control_flow"].append("for") + + elif node_type in ("while_statement", "while_expression"): + features["has_loop"] = True + features["cyclomatic_complexity"] += 1 + if "while" not in features["control_flow"]: + features["control_flow"].append("while") + + elif node_type in ("match_statement", "match_expression", "switch_statement"): + features["cyclomatic_complexity"] += 1 + if "match" not in features["control_flow"]: + features["control_flow"].append("match") + + elif node_type in ("try_statement", "try_expression"): + if "try" not in features["control_flow"]: + features["control_flow"].append("try") + + elif node_type in ("return_statement",): + if "return" not in features["control_flow"]: + features["control_flow"].append("return") + + elif node_type in ("yield_expression", "yield_statement"): + if "yield" not in features["control_flow"]: + features["control_flow"].append("yield") + + # Detect nesting for block-like nodes + is_block = node_type in ( + "block", "statement_block", "compound_statement", "body", + "function_body", "class_body", "do_block", + ) + + for child in node.children: + _analyze_node(child, features, depth + (1 if is_block else 0)) + + +def _extract_features_heuristic(code: str, features: dict) -> dict: + """Heuristic feature extraction when tree-sitter is unavailable.""" + lines = code.split("\n") + for line in lines: + stripped = line.strip() + if any(kw in stripped for kw in ("if ", "if(", "elif ", "else if")): + features["has_conditional"] = True + features["cyclomatic_complexity"] += 1 + if any(kw in stripped for kw in ("for ", "for(", "while ", "while(", "loop ")): + features["has_loop"] = True + features["cyclomatic_complexity"] += 1 + return features + + +def _compute_similarity(a: dict, b: dict) -> float: + """Compute structural similarity score between 0 and 1.""" + scores = [] + + # Parameter count similarity + if a["param_count"] == b["param_count"]: + scores.append(1.0) + else: + diff = abs(a["param_count"] - b["param_count"]) + scores.append(max(0, 1.0 - diff * 0.2)) + + # Nesting depth similarity + depth_diff = abs(a["nesting_depth"] - b["nesting_depth"]) + scores.append(max(0, 1.0 - depth_diff * 0.15)) + + # Cyclomatic complexity similarity + max_cc = max(a["cyclomatic_complexity"], b["cyclomatic_complexity"], 1) + min_cc = min(a["cyclomatic_complexity"], b["cyclomatic_complexity"], 1) + scores.append(min_cc / max_cc) + + # Control flow overlap (Jaccard similarity) + set_a = set(a.get("control_flow", [])) + set_b = set(b.get("control_flow", [])) + if set_a or set_b: + scores.append(len(set_a & set_b) / len(set_a | set_b)) + else: + scores.append(1.0) + + # Line count similarity + max_lines = max(a["line_count"], b["line_count"], 1) + min_lines = min(a["line_count"], b["line_count"], 1) + scores.append(min_lines / max_lines) + + # Boolean feature matches + bool_features = ["has_loop", "has_conditional", "has_recursion"] + matches = sum(1 for f in bool_features if a.get(f) == b.get(f)) + scores.append(matches / len(bool_features)) + + return sum(scores) / len(scores) diff --git a/@ether/library/Index/requirements.txt b/@ether/library/Index/requirements.txt new file mode 100644 index 00000000..2c579363 --- /dev/null +++ b/@ether/library/Index/requirements.txt @@ -0,0 +1,15 @@ +tinygrad>=0.10.0 +lancedb>=0.15.0 +pyarrow>=14.0 +tree-sitter>=0.23.0 +tree-sitter-python>=0.23.0 +tree-sitter-javascript>=0.23.0 +tree-sitter-rust>=0.23.0 +tree-sitter-c>=0.23.0 +tree-sitter-go>=0.23.0 +tree-sitter-java>=0.23.0 +tree-sitter-typescript>=0.23.0 +tree-sitter-ruby>=0.23.0 +tree-sitter-haskell>=0.23.0 +fastapi>=0.115.0 +uvicorn>=0.30.0 diff --git a/@ether/library/Index/store/__init__.py b/@ether/library/Index/store/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/@ether/library/Index/store/schema.py b/@ether/library/Index/store/schema.py new file mode 100644 index 00000000..3e044d4f --- /dev/null +++ b/@ether/library/Index/store/schema.py @@ -0,0 +1,23 @@ +"""LanceDB table schema definition for code chunks.""" +from __future__ import annotations + +import pyarrow as pa + +from ..config import EMBEDDING_DIM + +# Schema for the code chunks table +CHUNKS_SCHEMA = pa.schema([ + pa.field("chunk_id", pa.string()), + pa.field("language", pa.string()), + pa.field("version", pa.string()), + pa.field("file_path", pa.string()), + pa.field("repo", pa.string()), + pa.field("start_line", pa.int32()), + pa.field("end_line", pa.int32()), + pa.field("ast_type", pa.string()), + pa.field("name", pa.string()), + pa.field("text", pa.string()), + pa.field("vector", pa.list_(pa.float32(), EMBEDDING_DIM)), +]) + +TABLE_NAME = "code_chunks" diff --git a/@ether/library/Index/store/vector_store.py b/@ether/library/Index/store/vector_store.py new file mode 100644 index 00000000..17df8a3d --- /dev/null +++ b/@ether/library/Index/store/vector_store.py @@ -0,0 +1,195 @@ +"""LanceDB wrapper for vector storage and search.""" +from __future__ import annotations + +from pathlib import Path +from typing import Any + +import numpy as np + +from ..config import VECTORS_DIR, EMBEDDING_DIM, ensure_dirs +from .schema import CHUNKS_SCHEMA, TABLE_NAME + + +class VectorStore: + """LanceDB-backed vector store for code chunk embeddings.""" + + def __init__(self, db_path: Path | None = None): + self._db_path = str(db_path or VECTORS_DIR) + self._db = None + self._table = None + + def _get_db(self): + if self._db is None: + import lancedb + ensure_dirs() + self._db = lancedb.connect(self._db_path) + return self._db + + def _get_table(self): + if self._table is None: + db = self._get_db() + try: + self._table = db.open_table(TABLE_NAME) + except Exception: + self._table = None + return self._table + + def _ensure_table(self): + """Get or create the table.""" + table = self._get_table() + if table is not None: + return table + db = self._get_db() + import pyarrow as pa + empty = pa.table({ + "chunk_id": pa.array([], type=pa.string()), + "language": pa.array([], type=pa.string()), + "version": pa.array([], type=pa.string()), + "file_path": pa.array([], type=pa.string()), + "repo": pa.array([], type=pa.string()), + "start_line": pa.array([], type=pa.int32()), + "end_line": pa.array([], type=pa.int32()), + "ast_type": pa.array([], type=pa.string()), + "name": pa.array([], type=pa.string()), + "text": pa.array([], type=pa.string()), + "vector": pa.array([], type=pa.list_(pa.float32(), EMBEDDING_DIM)), + }) + self._table = db.create_table(TABLE_NAME, data=empty, schema=CHUNKS_SCHEMA) + return self._table + + def insert(self, records: list[dict]) -> int: + """Insert code chunk records into the store. + + Each record should have: chunk_id, language, version, file_path, repo, + start_line, end_line, ast_type, name, text, vector. + + Returns: + Number of records inserted. + """ + if not records: + return 0 + table = self._ensure_table() + table.add(records) + return len(records) + + def search( + self, + query_vector: np.ndarray, + limit: int = 20, + language: str | None = None, + version: str | None = None, + ast_type: str | None = None, + repo: str | None = None, + exclude_languages: list[str] | None = None, + ) -> list[dict]: + """Search for similar code chunks. + + Args: + query_vector: Query embedding vector. + limit: Max results to return. + language: Filter to a specific language. + version: Filter to a specific version. + ast_type: Filter to a specific AST type (e.g. "function_definition"). + repo: Filter to a specific repo. + exclude_languages: Languages to exclude from results. + + Returns: + List of result dicts with metadata and _distance score. + """ + table = self._get_table() + if table is None: + return [] + + query = table.search(query_vector.tolist()).limit(limit) + + # Build where clause + filters = [] + if language: + filters.append(f"language = '{_escape(language)}'") + if version: + filters.append(f"version = '{_escape(version)}'") + if ast_type: + filters.append(f"ast_type = '{_escape(ast_type)}'") + if repo: + filters.append(f"repo = '{_escape(repo)}'") + if exclude_languages: + for lang in exclude_languages: + filters.append(f"language != '{_escape(lang)}'") + + if filters: + query = query.where(" AND ".join(filters)) + + results = query.to_list() + return results + + def count(self, language: str | None = None) -> int: + """Count records, optionally filtered by language.""" + table = self._get_table() + if table is None: + return 0 + if language: + return table.count_rows(f"language = '{_escape(language)}'") + return table.count_rows() + + def languages(self) -> list[dict]: + """Get list of indexed languages with chunk counts.""" + table = self._get_table() + if table is None: + return [] + try: + df = table.to_lance().to_table(columns=["language"]).to_pandas() + counts = df["language"].value_counts().to_dict() + except (ImportError, Exception): + # Fallback: query all records for language field + results = table.search().select(["language"]).limit(1_000_000).to_list() + counts: dict[str, int] = {} + for r in results: + lang = r.get("language", "") + counts[lang] = counts.get(lang, 0) + 1 + return [{"language": lang, "count": count} for lang, count in sorted(counts.items())] + + def stats(self) -> dict: + """Get index statistics.""" + table = self._get_table() + if table is None: + return {"total_chunks": 0, "languages": 0, "repos": 0} + try: + df = table.to_lance().to_table(columns=["language", "repo"]).to_pandas() + return { + "total_chunks": len(df), + "languages": df["language"].nunique(), + "repos": df["repo"].nunique(), + } + except (ImportError, Exception): + total = table.count_rows() + results = table.search().select(["language", "repo"]).limit(1_000_000).to_list() + languages = set(r.get("language", "") for r in results) + repos = set(r.get("repo", "") for r in results) + return { + "total_chunks": total, + "languages": len(languages), + "repos": len(repos), + } + + def delete_by_language(self, language: str) -> int: + """Delete all chunks for a language (for reindexing).""" + table = self._get_table() + if table is None: + return 0 + count = table.count_rows(f"language = '{_escape(language)}'") + table.delete(f"language = '{_escape(language)}'") + return count + + def delete_by_file(self, file_path: str) -> int: + """Delete all chunks for a specific file.""" + table = self._get_table() + if table is None: + return 0 + count = table.count_rows(f"file_path = '{_escape(file_path)}'") + table.delete(f"file_path = '{_escape(file_path)}'") + return count + + +def _escape(s: str) -> str: + """Escape single quotes for LanceDB SQL-like filters.""" + return s.replace("'", "''") diff --git a/@ether/library/Language/ACL2/check.sh b/@ether/library/Language/ACL2/check.sh new file mode 100755 index 00000000..b7e3b364 --- /dev/null +++ b/@ether/library/Language/ACL2/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/acl2/acl2" +[[ -x "$REPO_DIR/saved_acl2" ]] || command -v acl2 &>/dev/null diff --git a/@ether/library/Language/ACL2/install.sh b/@ether/library/Language/ACL2/install.sh new file mode 100755 index 00000000..4c499afc --- /dev/null +++ b/@ether/library/Language/ACL2/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +# ACL2 - A Computational Logic for Applicative Common Lisp +if [[ "${FROM_SOURCE:-false}" == "true" ]] || true; then + # ACL2 is typically built from source + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/acl2/acl2" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/acl2/acl2.git "$REPO_DIR" + fi + # Ensure SBCL is installed as the Common Lisp implementation + if ! command -v sbcl &>/dev/null; then + if [[ "$(uname)" == "Darwin" ]]; then + brew install sbcl + elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y sbcl + elif command -v dnf &>/dev/null; then + sudo dnf install -y sbcl + elif command -v pacman &>/dev/null; then + sudo pacman -S --noconfirm sbcl + else + echo "Please install SBCL first." >&2; exit 1 + fi + fi + cd "$REPO_DIR" + make LISP=sbcl +fi diff --git a/@ether/library/Language/ACL2/repl.sh b/@ether/library/Language/ACL2/repl.sh new file mode 100755 index 00000000..14fe3389 --- /dev/null +++ b/@ether/library/Language/ACL2/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/acl2/acl2" +if [[ -x "$REPO_DIR/saved_acl2" ]]; then + exec "$REPO_DIR/saved_acl2" +else + exec acl2 +fi diff --git a/@ether/library/Language/ACL2/run.sh b/@ether/library/Language/ACL2/run.sh new file mode 100755 index 00000000..6cc19244 --- /dev/null +++ b/@ether/library/Language/ACL2/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/acl2/acl2" +if [[ -x "$REPO_DIR/saved_acl2" ]]; then + exec "$REPO_DIR/saved_acl2" < "$1" +else + exec acl2 < "$1" +fi diff --git a/@ether/library/Language/ALF/check.sh b/@ether/library/Language/ALF/check.sh new file mode 100755 index 00000000..3d22c9d8 --- /dev/null +++ b/@ether/library/Language/ALF/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v alf &>/dev/null diff --git a/@ether/library/Language/ALF/install.sh b/@ether/library/Language/ALF/install.sh new file mode 100755 index 00000000..835b02f3 --- /dev/null +++ b/@ether/library/Language/ALF/install.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +# ALF - Another Logical Framework (historical proof assistant) +# ALF is a historical system; no modern package manager installation exists. +# Attempting from-source build from any available repository. +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ALF/alf" +echo "ALF is a historical proof assistant from Chalmers University." >&2 +echo "No modern package or maintained source repository is available." >&2 +echo "See: https://en.wikipedia.org/wiki/ALF_(proof_assistant)" >&2 +exit 1 diff --git a/@ether/library/Language/ALF/repl.sh b/@ether/library/Language/ALF/repl.sh new file mode 100755 index 00000000..4e722d59 --- /dev/null +++ b/@ether/library/Language/ALF/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for ALF." diff --git a/@ether/library/Language/ALF/run.sh b/@ether/library/Language/ALF/run.sh new file mode 100755 index 00000000..fb973a63 --- /dev/null +++ b/@ether/library/Language/ALF/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec alf "$1" diff --git a/@ether/library/Language/ALGOL/check.sh b/@ether/library/Language/ALGOL/check.sh new file mode 100755 index 00000000..5789d39c --- /dev/null +++ b/@ether/library/Language/ALGOL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v a68g &>/dev/null diff --git a/@ether/library/Language/ALGOL/install.sh b/@ether/library/Language/ALGOL/install.sh new file mode 100755 index 00000000..43db8a23 --- /dev/null +++ b/@ether/library/Language/ALGOL/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +# ALGOL 68 - algol68g interpreter +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/NevilleDNZ/algol68g-mirror" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/NevilleDNZ/algol68g-mirror.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./configure --prefix="$HOME/.local" + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install algol68g +elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y algol68g +elif command -v dnf &>/dev/null; then + sudo dnf install -y algol68g +elif command -v pacman &>/dev/null; then + echo "Install algol68g from AUR: yay -S algol68g" >&2; exit 1 +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/ALGOL/repl.sh b/@ether/library/Language/ALGOL/repl.sh new file mode 100755 index 00000000..ad8e555b --- /dev/null +++ b/@ether/library/Language/ALGOL/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec a68g --interactive diff --git a/@ether/library/Language/ALGOL/run.sh b/@ether/library/Language/ALGOL/run.sh new file mode 100755 index 00000000..2e492ff9 --- /dev/null +++ b/@ether/library/Language/ALGOL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec a68g "$1" diff --git a/@ether/library/Language/ANTLR/check.sh b/@ether/library/Language/ANTLR/check.sh new file mode 100755 index 00000000..450e3b18 --- /dev/null +++ b/@ether/library/Language/ANTLR/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v antlr4 &>/dev/null || command -v antlr &>/dev/null || python3 -c "import antlr4" 2>/dev/null diff --git a/@ether/library/Language/ANTLR/install.sh b/@ether/library/Language/ANTLR/install.sh new file mode 100755 index 00000000..3dfed93e --- /dev/null +++ b/@ether/library/Language/ANTLR/install.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail +# ANTLR - parser generator - https://www.antlr.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/antlr/antlr4" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/antlr/antlr4.git "$REPO_DIR" + fi + cd "$REPO_DIR" + mvn clean install -DskipTests || true + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install antlr +elif command -v pip3 &>/dev/null; then + pip3 install antlr4-tools +elif command -v pip &>/dev/null; then + pip install antlr4-tools +else + # Fallback: download jar directly + INSTALL_DIR="${ETHER_EXTERNAL_DIR:-$HOME/.local/share}/antlr" + mkdir -p "$INSTALL_DIR" + curl -fSL -o "$INSTALL_DIR/antlr.jar" "https://www.antlr.org/download/antlr-4.13.1-complete.jar" || { + echo "Failed to download ANTLR." >&2; exit 1 + } + echo "ANTLR installed at $INSTALL_DIR/antlr.jar" + echo "Run with: java -jar $INSTALL_DIR/antlr.jar" +fi diff --git a/@ether/library/Language/ANTLR/repl.sh b/@ether/library/Language/ANTLR/repl.sh new file mode 100755 index 00000000..c0dfd22e --- /dev/null +++ b/@ether/library/Language/ANTLR/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for ANTLR." diff --git a/@ether/library/Language/ANTLR/run.sh b/@ether/library/Language/ANTLR/run.sh new file mode 100755 index 00000000..c6060693 --- /dev/null +++ b/@ether/library/Language/ANTLR/run.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v antlr4 &>/dev/null; then + exec antlr4 "$1" +elif command -v antlr &>/dev/null; then + exec antlr "$1" +else + INSTALL_DIR="${ETHER_EXTERNAL_DIR:-$HOME/.local/share}/antlr" + exec java -jar "$INSTALL_DIR/antlr.jar" "$1" +fi diff --git a/@ether/library/Language/APL/check.sh b/@ether/library/Language/APL/check.sh new file mode 100755 index 00000000..e29dbda6 --- /dev/null +++ b/@ether/library/Language/APL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v apl &>/dev/null diff --git a/@ether/library/Language/APL/install.sh b/@ether/library/Language/APL/install.sh new file mode 100755 index 00000000..f1a428fd --- /dev/null +++ b/@ether/library/Language/APL/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +# APL - GNU APL interpreter +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/gnu-mirror-unofficial/apl" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/gnu-mirror-unofficial/apl.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./configure --prefix="$HOME/.local" + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install gnu-apl +elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y apl +elif command -v dnf &>/dev/null; then + sudo dnf install -y apl +elif command -v pacman &>/dev/null; then + sudo pacman -S --noconfirm apl +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/APL/repl.sh b/@ether/library/Language/APL/repl.sh new file mode 100755 index 00000000..f1c54fa2 --- /dev/null +++ b/@ether/library/Language/APL/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec apl diff --git a/@ether/library/Language/APL/run.sh b/@ether/library/Language/APL/run.sh new file mode 100755 index 00000000..768d42fa --- /dev/null +++ b/@ether/library/Language/APL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec apl --script -f "$1" diff --git a/@ether/library/Language/AQASM/check.sh b/@ether/library/Language/AQASM/check.sh new file mode 100755 index 00000000..97eab69b --- /dev/null +++ b/@ether/library/Language/AQASM/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import qat.lang.AQASM" 2>/dev/null diff --git a/@ether/library/Language/AQASM/install.sh b/@ether/library/Language/AQASM/install.sh new file mode 100755 index 00000000..44d76a7d --- /dev/null +++ b/@ether/library/Language/AQASM/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +# AQASM - Atos Quantum Assembly Language (part of myQLM) +pip3 install myqlm 2>/dev/null || pip install myqlm 2>/dev/null || { + echo "Failed to install myQLM. Ensure pip/pip3 is available." >&2; exit 1 +} diff --git a/@ether/library/Language/AQASM/repl.sh b/@ether/library/Language/AQASM/repl.sh new file mode 100755 index 00000000..94faa111 --- /dev/null +++ b/@ether/library/Language/AQASM/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "from qat.lang.AQASM import *; import code; code.interact(local=locals())" diff --git a/@ether/library/Language/AQASM/run.sh b/@ether/library/Language/AQASM/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/AQASM/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/ARMAssembly/check.sh b/@ether/library/Language/ARMAssembly/check.sh new file mode 100755 index 00000000..4ffdd978 --- /dev/null +++ b/@ether/library/Language/ARMAssembly/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v arm-linux-gnueabihf-as &>/dev/null || command -v aarch64-linux-gnu-as &>/dev/null || command -v arm-none-eabi-as &>/dev/null diff --git a/@ether/library/Language/ARMAssembly/install.sh b/@ether/library/Language/ARMAssembly/install.sh new file mode 100755 index 00000000..13057ed3 --- /dev/null +++ b/@ether/library/Language/ARMAssembly/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# ARM Assembly - cross-compiler toolchain +if [[ "$(uname)" == "Darwin" ]]; then + brew install arm-linux-gnueabihf-binutils 2>/dev/null || brew install binutils 2>/dev/null || true +elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y gcc-arm-linux-gnueabihf binutils-aarch64-linux-gnu qemu-user +elif command -v dnf &>/dev/null; then + sudo dnf install -y gcc-arm-linux-gnu binutils-aarch64-linux-gnu qemu-user +elif command -v pacman &>/dev/null; then + sudo pacman -S --noconfirm arm-none-eabi-gcc arm-none-eabi-binutils qemu-user +else + echo "Unsupported package manager. Please install ARM cross-compilation tools manually." >&2; exit 1 +fi diff --git a/@ether/library/Language/ARMAssembly/repl.sh b/@ether/library/Language/ARMAssembly/repl.sh new file mode 100755 index 00000000..b3601966 --- /dev/null +++ b/@ether/library/Language/ARMAssembly/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for ARM Assembly." diff --git a/@ether/library/Language/ARMAssembly/run.sh b/@ether/library/Language/ARMAssembly/run.sh new file mode 100755 index 00000000..38562e00 --- /dev/null +++ b/@ether/library/Language/ARMAssembly/run.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +FILE="$1" +BASE="${FILE%.*}" +if command -v aarch64-linux-gnu-as &>/dev/null; then + aarch64-linux-gnu-as -o "$BASE.o" "$FILE" + aarch64-linux-gnu-ld -o "$BASE" "$BASE.o" + exec qemu-aarch64 -L /usr/aarch64-linux-gnu "$BASE" +elif command -v arm-linux-gnueabihf-as &>/dev/null; then + arm-linux-gnueabihf-as -o "$BASE.o" "$FILE" + arm-linux-gnueabihf-ld -o "$BASE" "$BASE.o" + exec qemu-arm -L /usr/arm-linux-gnueabihf "$BASE" +else + echo "No ARM assembler found." >&2; exit 1 +fi diff --git a/@ether/library/Language/ASN/check.sh b/@ether/library/Language/ASN/check.sh new file mode 100755 index 00000000..583059e4 --- /dev/null +++ b/@ether/library/Language/ASN/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v asn1c &>/dev/null diff --git a/@ether/library/Language/ASN/install.sh b/@ether/library/Language/ASN/install.sh new file mode 100755 index 00000000..53e817f1 --- /dev/null +++ b/@ether/library/Language/ASN/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +# ASN.1 tools - asn1c compiler +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/vlm/asn1c" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/vlm/asn1c.git "$REPO_DIR" + fi + cd "$REPO_DIR" + autoreconf -iv + ./configure --prefix="$HOME/.local" + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install asn1c +elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y asn1c +elif command -v dnf &>/dev/null; then + sudo dnf install -y asn1c +elif command -v pacman &>/dev/null; then + sudo pacman -S --noconfirm asn1c +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/ASN/repl.sh b/@ether/library/Language/ASN/repl.sh new file mode 100755 index 00000000..c6b2434b --- /dev/null +++ b/@ether/library/Language/ASN/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for ASN.1." diff --git a/@ether/library/Language/ASN/run.sh b/@ether/library/Language/ASN/run.sh new file mode 100755 index 00000000..badf0af4 --- /dev/null +++ b/@ether/library/Language/ASN/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec asn1c "$1" diff --git a/@ether/library/Language/ATS/check.sh b/@ether/library/Language/ATS/check.sh new file mode 100755 index 00000000..f8ac0cad --- /dev/null +++ b/@ether/library/Language/ATS/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v patscc >/dev/null 2>&1 || command -v atscc >/dev/null 2>&1 diff --git a/@ether/library/Language/ATS/install.sh b/@ether/library/Language/ATS/install.sh new file mode 100755 index 00000000..8c845f80 --- /dev/null +++ b/@ether/library/Language/ATS/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# ATS - Applied Type System (ATS2/Postiats) +if [[ "$(uname)" == "Darwin" ]]; then + brew install ats2-postiats +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y ats2-lang +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y ats2-lang || true +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm ats2 || true +fi +# Fall back to from-source if package not available +if ! command -v patscc >/dev/null 2>&1; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/githwxi/ATS-Postiats" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/githwxi/ATS-Postiats.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./configure && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + sudo make install || cp bin/patscc "$HOME/.local/bin/" +fi diff --git a/@ether/library/Language/ATS/repl.sh b/@ether/library/Language/ATS/repl.sh new file mode 100755 index 00000000..8fa713a8 --- /dev/null +++ b/@ether/library/Language/ATS/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "ATS does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ATS/run.sh b/@ether/library/Language/ATS/run.sh new file mode 100755 index 00000000..63147dd3 --- /dev/null +++ b/@ether/library/Language/ATS/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v patscc >/dev/null 2>&1; then + patscc -o "${1%.dats}" "$1" && exec "./${1%.dats}" +elif command -v atscc >/dev/null 2>&1; then + atscc -o "${1%.dats}" "$1" && exec "./${1%.dats}" +else + echo "No ATS compiler found." >&2; exit 1 +fi diff --git a/@ether/library/Language/AWK/check.sh b/@ether/library/Language/AWK/check.sh new file mode 100755 index 00000000..e8dd52fd --- /dev/null +++ b/@ether/library/Language/AWK/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v awk >/dev/null 2>&1 || command -v gawk >/dev/null 2>&1 diff --git a/@ether/library/Language/AWK/install.sh b/@ether/library/Language/AWK/install.sh new file mode 100755 index 00000000..bb20485e --- /dev/null +++ b/@ether/library/Language/AWK/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# AWK - text processing language (GNU awk) +if [[ "$(uname)" == "Darwin" ]]; then + brew install gawk +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gawk +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gawk +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gawk +fi diff --git a/@ether/library/Language/AWK/repl.sh b/@ether/library/Language/AWK/repl.sh new file mode 100755 index 00000000..0d61115e --- /dev/null +++ b/@ether/library/Language/AWK/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "AWK does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/AWK/run.sh b/@ether/library/Language/AWK/run.sh new file mode 100755 index 00000000..fa1653d4 --- /dev/null +++ b/@ether/library/Language/AWK/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec awk -f "$1" diff --git a/@ether/library/Language/Abella/check.sh b/@ether/library/Language/Abella/check.sh new file mode 100755 index 00000000..5e358a0d --- /dev/null +++ b/@ether/library/Language/Abella/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v abella &>/dev/null diff --git a/@ether/library/Language/Abella/install.sh b/@ether/library/Language/Abella/install.sh new file mode 100755 index 00000000..a881d421 --- /dev/null +++ b/@ether/library/Language/Abella/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# Abella - interactive theorem prover - https://abella-prover.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/abella-prover/abella" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/abella-prover/abella.git "$REPO_DIR" + fi + cd "$REPO_DIR" + if command -v opam &>/dev/null; then + eval "$(opam env)" || true + opam install -y . --deps-only || true + fi + make && sudo make install || true + exit 0 +fi +if command -v opam &>/dev/null; then + eval "$(opam env)" || true + opam install -y abella +else + echo "opam is required. Install OCaml/opam first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Abella/repl.sh b/@ether/library/Language/Abella/repl.sh new file mode 100755 index 00000000..316c3e79 --- /dev/null +++ b/@ether/library/Language/Abella/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec abella diff --git a/@ether/library/Language/Abella/run.sh b/@ether/library/Language/Abella/run.sh new file mode 100755 index 00000000..776f1af8 --- /dev/null +++ b/@ether/library/Language/Abella/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec abella "$1" diff --git a/@ether/library/Language/Ada/check.sh b/@ether/library/Language/Ada/check.sh new file mode 100755 index 00000000..a78e86f0 --- /dev/null +++ b/@ether/library/Language/Ada/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v gnatmake &>/dev/null diff --git a/@ether/library/Language/Ada/install.sh b/@ether/library/Language/Ada/install.sh new file mode 100755 index 00000000..1c652872 --- /dev/null +++ b/@ether/library/Language/Ada/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Ada - GNAT compiler +if [[ "$(uname)" == "Darwin" ]]; then + brew install gcc +elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y gnat +elif command -v dnf &>/dev/null; then + sudo dnf install -y gcc-gnat +elif command -v pacman &>/dev/null; then + sudo pacman -S --noconfirm gcc-ada +else + echo "Unsupported package manager. Please install GNAT manually." >&2; exit 1 +fi diff --git a/@ether/library/Language/Ada/packages.sh b/@ether/library/Language/Ada/packages.sh new file mode 100755 index 00000000..698e1806 --- /dev/null +++ b/@ether/library/Language/Ada/packages.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://alire.ada.dev" + +usage() { + echo "Ada Package Registry (Alire):" + echo " $REGISTRY" + echo + echo "Usage: packages.sh {search|info|install} " +} + +cmd_search() { + if command -v alr &>/dev/null; then + alr search "$@" + else + echo "https://alire.ada.dev/crates?q=$1" + fi +} + +cmd_info() { + local pkg="$1" + if command -v alr &>/dev/null; then + alr show "$pkg" + else + echo "https://alire.ada.dev/crates/$pkg" + fi +} + +cmd_install() { + local pkg="$1" + if command -v alr &>/dev/null; then + echo "Getting via Alire..." + alr get "$pkg" + else + echo "Install Alire first: https://alire.ada.dev" + echo + echo "Then run:" + echo " alr get $pkg" + echo + echo "Or add dependency:" + echo " alr with $pkg" + echo + echo "Browse: https://alire.ada.dev/crates/$pkg" + fi +} + +case "${1:-}" in + search) shift; cmd_search "$@" ;; + info) shift; cmd_info "$1" ;; + install) shift; cmd_install "$1" ;; + *) usage ;; +esac diff --git a/@ether/library/Language/Ada/repl.sh b/@ether/library/Language/Ada/repl.sh new file mode 100755 index 00000000..7a1d5920 --- /dev/null +++ b/@ether/library/Language/Ada/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for Ada." diff --git a/@ether/library/Language/Ada/run.sh b/@ether/library/Language/Ada/run.sh new file mode 100755 index 00000000..06836712 --- /dev/null +++ b/@ether/library/Language/Ada/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +FILE="$1" +OUT="${FILE%.adb}" +gnatmake -o "$OUT" "$FILE" +exec "$OUT" diff --git a/@ether/library/Language/Aeneas/check.sh b/@ether/library/Language/Aeneas/check.sh new file mode 100755 index 00000000..71003fe5 --- /dev/null +++ b/@ether/library/Language/Aeneas/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v aeneas &>/dev/null diff --git a/@ether/library/Language/Aeneas/install.sh b/@ether/library/Language/Aeneas/install.sh new file mode 100755 index 00000000..6c05c15b --- /dev/null +++ b/@ether/library/Language/Aeneas/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Aeneas - Rust verification tool - https://github.com/AeneasVerif/aeneas +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/AeneasVerif/aeneas" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/AeneasVerif/aeneas.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v opam &>/dev/null; then + eval "$(opam env)" || true + opam install -y . --deps-only || true + make + sudo make install || cp -v _build/default/bin/aeneas.exe "$HOME/.local/bin/aeneas" 2>/dev/null || true +else + echo "Aeneas requires opam. Install OCaml/opam first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Aeneas/repl.sh b/@ether/library/Language/Aeneas/repl.sh new file mode 100755 index 00000000..70bd8c11 --- /dev/null +++ b/@ether/library/Language/Aeneas/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for Aeneas." diff --git a/@ether/library/Language/Aeneas/run.sh b/@ether/library/Language/Aeneas/run.sh new file mode 100755 index 00000000..2696626c --- /dev/null +++ b/@ether/library/Language/Aeneas/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec aeneas "$1" diff --git a/@ether/library/Language/Agda/check.sh b/@ether/library/Language/Agda/check.sh new file mode 100755 index 00000000..4034bea4 --- /dev/null +++ b/@ether/library/Language/Agda/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v agda >/dev/null 2>&1 diff --git a/@ether/library/Language/Agda/install.sh b/@ether/library/Language/Agda/install.sh new file mode 100755 index 00000000..d78b004c --- /dev/null +++ b/@ether/library/Language/Agda/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v cabal >/dev/null 2>&1; then + cabal update && cabal install Agda +elif command -v stack >/dev/null 2>&1; then + stack install Agda +elif [[ "$(uname)" == "Darwin" ]]; then + brew install agda +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y agda +else + echo "Install GHC/cabal first, then: cabal install Agda" >&2; exit 1 +fi diff --git a/@ether/library/Language/Agda/packages.sh b/@ether/library/Language/Agda/packages.sh new file mode 100755 index 00000000..e8383390 --- /dev/null +++ b/@ether/library/Language/Agda/packages.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRIES=( + "https://github.com/agda/agda-stdlib" + "https://github.com/agda/agda-categories" + "https://github.com/agda/cubical" +) + +usage() { + echo "Agda Package Sources:" + for url in "${REGISTRIES[@]}"; do echo " $url"; done + echo + echo "Community packages: https://wiki.portal.chalmers.se/agda/pmwiki.php?n=Libraries.Libraries" + echo + echo "Usage: packages.sh {search|info|install} " +} + +cmd_search() { + local q="$1" + echo "https://github.com/search?q=agda+$q&type=repositories" + echo "https://github.com/agda/agda-stdlib/search?q=$q" +} + +cmd_info() { + local pkg="$1" + echo "https://github.com/agda/$pkg" +} + +cmd_install() { + local pkg="$1" + echo "Agda libraries are typically installed manually:" + echo + echo " 1. Clone the library:" + echo " git clone https://github.com/agda/$pkg.git" + echo + echo " 2. Register in ~/.agda/libraries:" + echo " /path/to/$pkg/$pkg.agda-lib" + echo + echo " 3. Add to ~/.agda/defaults:" + echo " $pkg" + echo + echo " Standard library: https://github.com/agda/agda-stdlib" +} + +case "${1:-}" in + search) shift; cmd_search "$1" ;; + info) shift; cmd_info "$1" ;; + install) shift; cmd_install "$1" ;; + *) usage ;; +esac diff --git a/@ether/library/Language/Agda/repl.sh b/@ether/library/Language/Agda/repl.sh new file mode 100755 index 00000000..2c5d5eb8 --- /dev/null +++ b/@ether/library/Language/Agda/repl.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v agda >/dev/null 2>&1; then + exec agda --interaction "$@" +else + echo "Agda is not installed." + echo "Agda is best used interactively via Emacs (agda-mode) or VS Code." + exit 1 +fi diff --git a/@ether/library/Language/Agda/run.sh b/@ether/library/Language/Agda/run.sh new file mode 100755 index 00000000..4747e7ae --- /dev/null +++ b/@ether/library/Language/Agda/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec agda "$@" diff --git a/@ether/library/Language/Aiken/check.sh b/@ether/library/Language/Aiken/check.sh new file mode 100755 index 00000000..ff2cc240 --- /dev/null +++ b/@ether/library/Language/Aiken/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v aiken >/dev/null 2>&1 diff --git a/@ether/library/Language/Aiken/install.sh b/@ether/library/Language/Aiken/install.sh new file mode 100755 index 00000000..e6474ecc --- /dev/null +++ b/@ether/library/Language/Aiken/install.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +# Aiken: Cardano smart contract language - https://aiken-lang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/aiken-lang/aiken" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/aiken-lang/aiken.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + exit 0 +fi +if command -v cargo >/dev/null 2>&1; then + cargo install aiken +elif command -v curl >/dev/null 2>&1; then + curl -sSfL https://install.aiken-lang.org | bash +else + echo "Install Rust/Cargo first, then run: cargo install aiken" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Aiken/packages.sh b/@ether/library/Language/Aiken/packages.sh new file mode 100755 index 00000000..881e0685 --- /dev/null +++ b/@ether/library/Language/Aiken/packages.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Aiken" +REGISTRIES=( + "Aiken Ecosystem: https://aiken-lang.org/ecosystem" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v aiken &>/dev/null; then + aiken packages search "$@" + else + echo "Visit: https://aiken-lang.org/ecosystem" + echo "Search GitHub: https://github.com/search?q=aiken+$1&type=repositories" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://aiken-lang.org/ecosystem" + echo "Check: https://github.com/search?q=aiken+$1&type=repositories" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + if command -v aiken &>/dev/null; then + aiken packages add "$1" + else + echo "aiken not found. Install it first:" + echo " cargo install aiken" + echo "" + echo "Then run: aiken packages add $1" + fi + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Aiken/repl.sh b/@ether/library/Language/Aiken/repl.sh new file mode 100755 index 00000000..7dedf338 --- /dev/null +++ b/@ether/library/Language/Aiken/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Aiken does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Aiken/run.sh b/@ether/library/Language/Aiken/run.sh new file mode 100755 index 00000000..1056ed3f --- /dev/null +++ b/@ether/library/Language/Aiken/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec aiken build "$@" diff --git a/@ether/library/Language/Alchemy/check.sh b/@ether/library/Language/Alchemy/check.sh new file mode 100755 index 00000000..da644e78 --- /dev/null +++ b/@ether/library/Language/Alchemy/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v alchemy &>/dev/null || python3 -c "import alchemy" 2>/dev/null diff --git a/@ether/library/Language/Alchemy/install.sh b/@ether/library/Language/Alchemy/install.sh new file mode 100755 index 00000000..ce140c37 --- /dev/null +++ b/@ether/library/Language/Alchemy/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Alchemy - probabilistic programming / Markov Logic Networks +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/furushchev/alchemy-2" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/furushchev/alchemy-2.git "$REPO_DIR" + fi + cd "$REPO_DIR" + if [[ -d src ]]; then + cd src && make + sudo cp ../bin/* /usr/local/bin/ || cp ../bin/* "$HOME/.local/bin/" || true + fi + exit 0 +fi +pip install alchemy 2>/dev/null || pip3 install alchemy 2>/dev/null || { + echo "pip install failed. Try FROM_SOURCE=true." >&2; exit 1 +} diff --git a/@ether/library/Language/Alchemy/repl.sh b/@ether/library/Language/Alchemy/repl.sh new file mode 100755 index 00000000..0da614c9 --- /dev/null +++ b/@ether/library/Language/Alchemy/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for Alchemy." diff --git a/@ether/library/Language/Alchemy/run.sh b/@ether/library/Language/Alchemy/run.sh new file mode 100755 index 00000000..954c412e --- /dev/null +++ b/@ether/library/Language/Alchemy/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v alchemy &>/dev/null; then + exec alchemy "$1" +else + exec python3 "$1" +fi diff --git a/@ether/library/Language/Aletha/check.sh b/@ether/library/Language/Aletha/check.sh new file mode 100755 index 00000000..561ac258 --- /dev/null +++ b/@ether/library/Language/Aletha/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v aletha &>/dev/null diff --git a/@ether/library/Language/Aletha/install.sh b/@ether/library/Language/Aletha/install.sh new file mode 100755 index 00000000..240925f7 --- /dev/null +++ b/@ether/library/Language/Aletha/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Aletha - proof checker (OCaml-based) +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/aeqe/aletha" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/aeqe/aletha.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v opam &>/dev/null; then + eval "$(opam env)" || true + opam install -y . --deps-only || true + dune build 2>/dev/null || make 2>/dev/null || true + dune install 2>/dev/null || sudo make install 2>/dev/null || true +else + echo "opam is required. Install OCaml/opam first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Aletha/repl.sh b/@ether/library/Language/Aletha/repl.sh new file mode 100755 index 00000000..0183bd1d --- /dev/null +++ b/@ether/library/Language/Aletha/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for Aletha." diff --git a/@ether/library/Language/Aletha/run.sh b/@ether/library/Language/Aletha/run.sh new file mode 100755 index 00000000..1df97464 --- /dev/null +++ b/@ether/library/Language/Aletha/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec aletha "$1" diff --git a/@ether/library/Language/Alice/check.sh b/@ether/library/Language/Alice/check.sh new file mode 100755 index 00000000..0f6e96cc --- /dev/null +++ b/@ether/library/Language/Alice/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v alice &>/dev/null diff --git a/@ether/library/Language/Alice/install.sh b/@ether/library/Language/Alice/install.sh new file mode 100755 index 00000000..3cc03f95 --- /dev/null +++ b/@ether/library/Language/Alice/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +# Alice ML - functional programming language (successor to SML) +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/aliceml/aliceml" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/aliceml/aliceml.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if [[ -f Makefile ]]; then + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" || true + sudo make install || true +elif [[ -f configure ]]; then + ./configure --prefix="$HOME/.local" + make && make install +fi diff --git a/@ether/library/Language/Alice/repl.sh b/@ether/library/Language/Alice/repl.sh new file mode 100755 index 00000000..bac24ade --- /dev/null +++ b/@ether/library/Language/Alice/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec alice diff --git a/@ether/library/Language/Alice/run.sh b/@ether/library/Language/Alice/run.sh new file mode 100755 index 00000000..7963d52d --- /dev/null +++ b/@ether/library/Language/Alice/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec alice "$1" diff --git a/@ether/library/Language/Alloy/check.sh b/@ether/library/Language/Alloy/check.sh new file mode 100755 index 00000000..77b681e8 --- /dev/null +++ b/@ether/library/Language/Alloy/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +INSTALL_DIR="${ETHER_EXTERNAL_DIR:-$HOME/.local/share}/alloy" +[[ -f "$INSTALL_DIR/alloy.jar" ]] || command -v alloy &>/dev/null diff --git a/@ether/library/Language/Alloy/install.sh b/@ether/library/Language/Alloy/install.sh new file mode 100755 index 00000000..a178ddae --- /dev/null +++ b/@ether/library/Language/Alloy/install.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +# Alloy - lightweight formal modelling language / model checker +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/AlloyTools/org.alloytools.alloy" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/AlloyTools/org.alloytools.alloy.git "$REPO_DIR" + fi + cd "$REPO_DIR" + if [[ -f gradlew ]]; then + ./gradlew build -x test || true + elif command -v gradle &>/dev/null; then + gradle build -x test || true + fi + exit 0 +fi +# Download the Alloy jar directly +INSTALL_DIR="${ETHER_EXTERNAL_DIR:-$HOME/.local/share}/alloy" +mkdir -p "$INSTALL_DIR" +if ! command -v java &>/dev/null; then + echo "Java is required. Install a JDK first." >&2; exit 1 +fi +ALLOY_JAR="$INSTALL_DIR/alloy.jar" +if [[ ! -f "$ALLOY_JAR" ]]; then + curl -fSL -o "$ALLOY_JAR" "https://github.com/AlloyTools/org.alloytools.alloy/releases/latest/download/org.alloytools.alloy.dist.jar" || { + echo "Failed to download Alloy jar." >&2; exit 1 + } +fi +echo "Alloy installed at $ALLOY_JAR" +echo "Run with: java -jar $ALLOY_JAR" diff --git a/@ether/library/Language/Alloy/repl.sh b/@ether/library/Language/Alloy/repl.sh new file mode 100755 index 00000000..34ad7b94 --- /dev/null +++ b/@ether/library/Language/Alloy/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for Alloy. Use the Alloy Analyzer GUI." diff --git a/@ether/library/Language/Alloy/run.sh b/@ether/library/Language/Alloy/run.sh new file mode 100755 index 00000000..7f14c31d --- /dev/null +++ b/@ether/library/Language/Alloy/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +INSTALL_DIR="${ETHER_EXTERNAL_DIR:-$HOME/.local/share}/alloy" +if [[ -f "$INSTALL_DIR/alloy.jar" ]]; then + exec java -jar "$INSTALL_DIR/alloy.jar" "$1" +else + exec alloy "$1" +fi diff --git a/@ether/library/Language/AltErgo/check.sh b/@ether/library/Language/AltErgo/check.sh new file mode 100755 index 00000000..b5ec9662 --- /dev/null +++ b/@ether/library/Language/AltErgo/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v alt-ergo &>/dev/null diff --git a/@ether/library/Language/AltErgo/install.sh b/@ether/library/Language/AltErgo/install.sh new file mode 100755 index 00000000..3e16cbff --- /dev/null +++ b/@ether/library/Language/AltErgo/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# Alt-Ergo - SMT solver - https://alt-ergo.ocamlpro.com/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/OCamlPro/alt-ergo" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/OCamlPro/alt-ergo.git "$REPO_DIR" + fi + cd "$REPO_DIR" + if command -v opam &>/dev/null; then + eval "$(opam env)" || true + opam install -y . --deps-only || true + dune build && dune install + fi + exit 0 +fi +if command -v opam &>/dev/null; then + eval "$(opam env)" || true + opam install -y alt-ergo +else + echo "opam is required. Install OCaml/opam first." >&2; exit 1 +fi diff --git a/@ether/library/Language/AltErgo/repl.sh b/@ether/library/Language/AltErgo/repl.sh new file mode 100755 index 00000000..b6421cd4 --- /dev/null +++ b/@ether/library/Language/AltErgo/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for Alt-Ergo." diff --git a/@ether/library/Language/AltErgo/run.sh b/@ether/library/Language/AltErgo/run.sh new file mode 100755 index 00000000..7cdf5cb2 --- /dev/null +++ b/@ether/library/Language/AltErgo/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec alt-ergo "$1" diff --git a/@ether/library/Language/Amulet/check.sh b/@ether/library/Language/Amulet/check.sh new file mode 100755 index 00000000..9c0851b5 --- /dev/null +++ b/@ether/library/Language/Amulet/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v amc &>/dev/null diff --git a/@ether/library/Language/Amulet/install.sh b/@ether/library/Language/Amulet/install.sh new file mode 100755 index 00000000..9b83d2bb --- /dev/null +++ b/@ether/library/Language/Amulet/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Amulet - ML-like language - https://github.com/amuletml/amulet +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/amuletml/amulet" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/amuletml/amulet.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v stack &>/dev/null; then + stack build + stack install +elif command -v cabal &>/dev/null; then + cabal update && cabal build && cabal install +else + echo "Haskell Stack or Cabal is required." >&2; exit 1 +fi diff --git a/@ether/library/Language/Amulet/repl.sh b/@ether/library/Language/Amulet/repl.sh new file mode 100755 index 00000000..a099916a --- /dev/null +++ b/@ether/library/Language/Amulet/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec amc repl diff --git a/@ether/library/Language/Amulet/run.sh b/@ether/library/Language/Amulet/run.sh new file mode 100755 index 00000000..19a5f004 --- /dev/null +++ b/@ether/library/Language/Amulet/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec amc compile "$1" diff --git a/@ether/library/Language/Analytica/check.sh b/@ether/library/Language/Analytica/check.sh new file mode 100755 index 00000000..e0aa480d --- /dev/null +++ b/@ether/library/Language/Analytica/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v analytica &>/dev/null diff --git a/@ether/library/Language/Analytica/install.sh b/@ether/library/Language/Analytica/install.sh new file mode 100755 index 00000000..223878b5 --- /dev/null +++ b/@ether/library/Language/Analytica/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +# Analytica - decision analysis tool (commercial software) +echo "Analytica is commercial software by Lumina Decision Systems." >&2 +echo "Download from: https://lumina.com/analytica/" >&2 +exit 1 diff --git a/@ether/library/Language/Analytica/repl.sh b/@ether/library/Language/Analytica/repl.sh new file mode 100755 index 00000000..5778e647 --- /dev/null +++ b/@ether/library/Language/Analytica/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for Analytica." diff --git a/@ether/library/Language/Analytica/run.sh b/@ether/library/Language/Analytica/run.sh new file mode 100755 index 00000000..c1762915 --- /dev/null +++ b/@ether/library/Language/Analytica/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec analytica "$1" diff --git a/@ether/library/Language/Andromeda/check.sh b/@ether/library/Language/Andromeda/check.sh new file mode 100755 index 00000000..3f1af355 --- /dev/null +++ b/@ether/library/Language/Andromeda/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v andromeda &>/dev/null diff --git a/@ether/library/Language/Andromeda/install.sh b/@ether/library/Language/Andromeda/install.sh new file mode 100755 index 00000000..fefbc2d0 --- /dev/null +++ b/@ether/library/Language/Andromeda/install.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +# Andromeda - type theory with equality reflection - https://github.com/Andromedans/andromeda +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Andromedans/andromeda" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Andromedans/andromeda.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v opam &>/dev/null; then + eval "$(opam env)" || true + opam install -y . --deps-only || true + if [[ -f Makefile ]]; then + make && sudo make install || true + elif [[ -f dune-project ]]; then + dune build && dune install || true + fi +else + echo "opam is required. Install OCaml/opam first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Andromeda/repl.sh b/@ether/library/Language/Andromeda/repl.sh new file mode 100755 index 00000000..f0c19dc9 --- /dev/null +++ b/@ether/library/Language/Andromeda/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec andromeda diff --git a/@ether/library/Language/Andromeda/run.sh b/@ether/library/Language/Andromeda/run.sh new file mode 100755 index 00000000..8f4f31aa --- /dev/null +++ b/@ether/library/Language/Andromeda/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec andromeda "$1" diff --git a/@ether/library/Language/Anglican/check.sh b/@ether/library/Language/Anglican/check.sh new file mode 100755 index 00000000..6bc28f0c --- /dev/null +++ b/@ether/library/Language/Anglican/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/probprog/anglican" +[[ -d "$REPO_DIR" ]] && command -v lein &>/dev/null diff --git a/@ether/library/Language/Anglican/install.sh b/@ether/library/Language/Anglican/install.sh new file mode 100755 index 00000000..c471fbc2 --- /dev/null +++ b/@ether/library/Language/Anglican/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# Anglican - probabilistic programming (Clojure-based) +# Requires Leiningen (Clojure build tool) +if ! command -v lein &>/dev/null; then + if [[ "$(uname)" == "Darwin" ]]; then + brew install leiningen + elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y leiningen + elif command -v dnf &>/dev/null; then + sudo dnf install -y leiningen + elif command -v pacman &>/dev/null; then + sudo pacman -S --noconfirm leiningen + else + echo "Please install Leiningen first: https://leiningen.org/" >&2; exit 1 + fi +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/probprog/anglican" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/probprog/anglican.git "$REPO_DIR" +fi +cd "$REPO_DIR" +lein install diff --git a/@ether/library/Language/Anglican/repl.sh b/@ether/library/Language/Anglican/repl.sh new file mode 100755 index 00000000..1d543bb9 --- /dev/null +++ b/@ether/library/Language/Anglican/repl.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/probprog/anglican" +cd "$REPO_DIR" +exec lein repl diff --git a/@ether/library/Language/Anglican/run.sh b/@ether/library/Language/Anglican/run.sh new file mode 100755 index 00000000..74a79f46 --- /dev/null +++ b/@ether/library/Language/Anglican/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/probprog/anglican" +cd "$REPO_DIR" +exec lein run "$1" diff --git a/@ether/library/Language/Arc/check.sh b/@ether/library/Language/Arc/check.sh new file mode 100755 index 00000000..0d86f5e3 --- /dev/null +++ b/@ether/library/Language/Arc/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/arclanguage/anarern" +[[ -f "$REPO_DIR/as.scm" ]] && command -v racket &>/dev/null diff --git a/@ether/library/Language/Arc/install.sh b/@ether/library/Language/Arc/install.sh new file mode 100755 index 00000000..926f5ae6 --- /dev/null +++ b/@ether/library/Language/Arc/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# Arc - Lisp dialect by Paul Graham - http://arclanguage.org/ +# Requires Racket +if ! command -v racket &>/dev/null; then + if [[ "$(uname)" == "Darwin" ]]; then + brew install racket + elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y racket + elif command -v dnf &>/dev/null; then + sudo dnf install -y racket + elif command -v pacman &>/dev/null; then + sudo pacman -S --noconfirm racket + else + echo "Please install Racket first." >&2; exit 1 + fi +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/arclanguage/anarern" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/arclanguage/anarern.git "$REPO_DIR" +fi +echo "Arc installed at $REPO_DIR" +echo "Run with: cd $REPO_DIR && racket -f as.scm" diff --git a/@ether/library/Language/Arc/repl.sh b/@ether/library/Language/Arc/repl.sh new file mode 100755 index 00000000..b8fb0d7b --- /dev/null +++ b/@ether/library/Language/Arc/repl.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/arclanguage/anarern" +cd "$REPO_DIR" +exec racket -f as.scm diff --git a/@ether/library/Language/Arc/run.sh b/@ether/library/Language/Arc/run.sh new file mode 100755 index 00000000..59481e1a --- /dev/null +++ b/@ether/library/Language/Arc/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/arclanguage/anarern" +cd "$REPO_DIR" +exec racket -f as.scm -e "(load \"$1\")" diff --git a/@ether/library/Language/ArchSAT/check.sh b/@ether/library/Language/ArchSAT/check.sh new file mode 100755 index 00000000..f456fd88 --- /dev/null +++ b/@ether/library/Language/ArchSAT/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v archsat &>/dev/null diff --git a/@ether/library/Language/ArchSAT/install.sh b/@ether/library/Language/ArchSAT/install.sh new file mode 100755 index 00000000..7e3fbcaf --- /dev/null +++ b/@ether/library/Language/ArchSAT/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# ArchSAT - SAT/SMT solver with proof output +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Gbury/archsat" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Gbury/archsat.git "$REPO_DIR" + fi + cd "$REPO_DIR" + if command -v opam &>/dev/null; then + eval "$(opam env)" || true + opam install -y . --deps-only || true + make && sudo make install || true + fi + exit 0 +fi +if command -v opam &>/dev/null; then + eval "$(opam env)" || true + opam install -y archsat +else + echo "opam is required. Install OCaml/opam first." >&2; exit 1 +fi diff --git a/@ether/library/Language/ArchSAT/repl.sh b/@ether/library/Language/ArchSAT/repl.sh new file mode 100755 index 00000000..2a6c1881 --- /dev/null +++ b/@ether/library/Language/ArchSAT/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for ArchSAT." diff --git a/@ether/library/Language/ArchSAT/run.sh b/@ether/library/Language/ArchSAT/run.sh new file mode 100755 index 00000000..35e4ae21 --- /dev/null +++ b/@ether/library/Language/ArchSAT/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec archsat "$1" diff --git a/@ether/library/Language/Archetype/check.sh b/@ether/library/Language/Archetype/check.sh new file mode 100755 index 00000000..837063d3 --- /dev/null +++ b/@ether/library/Language/Archetype/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v archetype >/dev/null 2>&1 diff --git a/@ether/library/Language/Archetype/install.sh b/@ether/library/Language/Archetype/install.sh new file mode 100755 index 00000000..c2a678dd --- /dev/null +++ b/@ether/library/Language/Archetype/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Archetype: Tezos smart contract language - https://archetype-lang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/edukera/archetype-lang" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/edukera/archetype-lang.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make build + exit 0 +fi +npm install -g @completium/archetype-cli diff --git a/@ether/library/Language/Archetype/packages.sh b/@ether/library/Language/Archetype/packages.sh new file mode 100755 index 00000000..2724ef9a --- /dev/null +++ b/@ether/library/Language/Archetype/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Archetype does not have a standard package manager." +echo "Completium templates: https://completium.com" diff --git a/@ether/library/Language/Archetype/repl.sh b/@ether/library/Language/Archetype/repl.sh new file mode 100755 index 00000000..2032a5d5 --- /dev/null +++ b/@ether/library/Language/Archetype/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Archetype does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Archetype/run.sh b/@ether/library/Language/Archetype/run.sh new file mode 100755 index 00000000..0951fa91 --- /dev/null +++ b/@ether/library/Language/Archetype/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec archetype "$@" diff --git a/@ether/library/Language/Arend/check.sh b/@ether/library/Language/Arend/check.sh new file mode 100755 index 00000000..ed846ed0 --- /dev/null +++ b/@ether/library/Language/Arend/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +INSTALL_DIR="${ETHER_EXTERNAL_DIR:-$HOME/.local/share}/arend" +[[ -f "$INSTALL_DIR/Arend.jar" ]] && command -v java &>/dev/null diff --git a/@ether/library/Language/Arend/install.sh b/@ether/library/Language/Arend/install.sh new file mode 100755 index 00000000..c9a55248 --- /dev/null +++ b/@ether/library/Language/Arend/install.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail +# Arend - proof assistant based on HoTT - https://arend-lang.github.io/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/JetBrains/Arend" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/JetBrains/Arend.git "$REPO_DIR" + fi + cd "$REPO_DIR" + if [[ -f gradlew ]]; then + ./gradlew build -x test + elif command -v gradle &>/dev/null; then + gradle build -x test + fi + exit 0 +fi +# Download the Arend jar +INSTALL_DIR="${ETHER_EXTERNAL_DIR:-$HOME/.local/share}/arend" +mkdir -p "$INSTALL_DIR" +if ! command -v java &>/dev/null; then + echo "Java is required. Install a JDK first." >&2; exit 1 +fi +AREND_JAR="$INSTALL_DIR/Arend.jar" +if [[ ! -f "$AREND_JAR" ]]; then + curl -fSL -o "$AREND_JAR" "https://github.com/JetBrains/Arend/releases/latest/download/Arend.jar" || { + echo "Failed to download Arend jar." >&2; exit 1 + } +fi +echo "Arend installed at $AREND_JAR" diff --git a/@ether/library/Language/Arend/repl.sh b/@ether/library/Language/Arend/repl.sh new file mode 100755 index 00000000..1b898830 --- /dev/null +++ b/@ether/library/Language/Arend/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +INSTALL_DIR="${ETHER_EXTERNAL_DIR:-$HOME/.local/share}/arend" +exec java -jar "$INSTALL_DIR/Arend.jar" --repl diff --git a/@ether/library/Language/Arend/run.sh b/@ether/library/Language/Arend/run.sh new file mode 100755 index 00000000..a4665de3 --- /dev/null +++ b/@ether/library/Language/Arend/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +INSTALL_DIR="${ETHER_EXTERNAL_DIR:-$HOME/.local/share}/arend" +exec java -jar "$INSTALL_DIR/Arend.jar" "$1" diff --git a/@ether/library/Language/ArnoldC/check.sh b/@ether/library/Language/ArnoldC/check.sh new file mode 100755 index 00000000..1113c023 --- /dev/null +++ b/@ether/library/Language/ArnoldC/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/lhartikk/ArnoldC" +ARNOLDC_JAR=$(find "$REPO_DIR" -name "ArnoldC*.jar" 2>/dev/null | head -1) +[[ -n "$ARNOLDC_JAR" ]] && command -v java &>/dev/null diff --git a/@ether/library/Language/ArnoldC/install.sh b/@ether/library/Language/ArnoldC/install.sh new file mode 100755 index 00000000..7281c84c --- /dev/null +++ b/@ether/library/Language/ArnoldC/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +# ArnoldC - joke programming language based on Arnold Schwarzenegger quotes +# https://github.com/lhartikk/ArnoldC +if ! command -v java &>/dev/null; then + echo "Java is required. Install a JDK first." >&2; exit 1 +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/lhartikk/ArnoldC" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/lhartikk/ArnoldC.git "$REPO_DIR" +fi +cd "$REPO_DIR" +# Build with Maven or Gradle if available +if [[ -f pom.xml ]] && command -v mvn &>/dev/null; then + mvn package -DskipTests || true +elif [[ -f build.gradle ]] && command -v gradle &>/dev/null; then + gradle build -x test || true +elif [[ -f gradlew ]]; then + ./gradlew build -x test || true +fi +echo "ArnoldC installed at $REPO_DIR" diff --git a/@ether/library/Language/ArnoldC/repl.sh b/@ether/library/Language/ArnoldC/repl.sh new file mode 100755 index 00000000..4ecdd898 --- /dev/null +++ b/@ether/library/Language/ArnoldC/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for ArnoldC." diff --git a/@ether/library/Language/ArnoldC/run.sh b/@ether/library/Language/ArnoldC/run.sh new file mode 100755 index 00000000..d6caf623 --- /dev/null +++ b/@ether/library/Language/ArnoldC/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/lhartikk/ArnoldC" +ARNOLDC_JAR=$(find "$REPO_DIR" -name "ArnoldC*.jar" 2>/dev/null | head -1) +if [[ -n "$ARNOLDC_JAR" ]]; then + exec java -jar "$ARNOLDC_JAR" "$1" +else + echo "ArnoldC jar not found. Run install.sh first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Arturo/check.sh b/@ether/library/Language/Arturo/check.sh new file mode 100755 index 00000000..88d58920 --- /dev/null +++ b/@ether/library/Language/Arturo/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v arturo >/dev/null 2>&1 diff --git a/@ether/library/Language/Arturo/install.sh b/@ether/library/Language/Arturo/install.sh new file mode 100755 index 00000000..bbe05cba --- /dev/null +++ b/@ether/library/Language/Arturo/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Arturo programming language +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Arturo from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/arturo-lang/arturo" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/arturo-lang/arturo.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./build.sh + sudo cp bin/arturo /usr/local/bin/ + exit 0 +fi +# Official installer +curl -sSL https://get.arturo-lang.io | sh diff --git a/@ether/library/Language/Arturo/packages.sh b/@ether/library/Language/Arturo/packages.sh new file mode 100755 index 00000000..b22cbcd8 --- /dev/null +++ b/@ether/library/Language/Arturo/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Arturo does not have a standard package manager." +echo "https://github.com/arturo-lang/arturo" diff --git a/@ether/library/Language/Arturo/repl.sh b/@ether/library/Language/Arturo/repl.sh new file mode 100755 index 00000000..3ae46638 --- /dev/null +++ b/@ether/library/Language/Arturo/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec arturo diff --git a/@ether/library/Language/Arturo/run.sh b/@ether/library/Language/Arturo/run.sh new file mode 100755 index 00000000..9e2523f6 --- /dev/null +++ b/@ether/library/Language/Arturo/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec arturo "$@" diff --git a/@ether/library/Language/Assembly/check.sh b/@ether/library/Language/Assembly/check.sh new file mode 100755 index 00000000..994b5ab6 --- /dev/null +++ b/@ether/library/Language/Assembly/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nasm &>/dev/null || command -v yasm &>/dev/null || command -v as &>/dev/null diff --git a/@ether/library/Language/Assembly/install.sh b/@ether/library/Language/Assembly/install.sh new file mode 100755 index 00000000..5e4b5826 --- /dev/null +++ b/@ether/library/Language/Assembly/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +# Assembly - NASM/YASM/GAS assembler +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/netwide-assembler/nasm" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/netwide-assembler/nasm.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./autogen.sh + ./configure --prefix="$HOME/.local" + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install nasm +elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y nasm +elif command -v dnf &>/dev/null; then + sudo dnf install -y nasm +elif command -v pacman &>/dev/null; then + sudo pacman -S --noconfirm nasm +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/Assembly/repl.sh b/@ether/library/Language/Assembly/repl.sh new file mode 100755 index 00000000..27dde434 --- /dev/null +++ b/@ether/library/Language/Assembly/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "No REPL available for Assembly." diff --git a/@ether/library/Language/Assembly/run.sh b/@ether/library/Language/Assembly/run.sh new file mode 100755 index 00000000..d063a883 --- /dev/null +++ b/@ether/library/Language/Assembly/run.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +FILE="$1" +BASE="${FILE%.*}" +if command -v nasm &>/dev/null; then + nasm -f elf64 -o "$BASE.o" "$FILE" + ld -o "$BASE" "$BASE.o" + exec "$BASE" +elif command -v yasm &>/dev/null; then + yasm -f elf64 -o "$BASE.o" "$FILE" + ld -o "$BASE" "$BASE.o" + exec "$BASE" +else + as -o "$BASE.o" "$FILE" + ld -o "$BASE" "$BASE.o" + exec "$BASE" +fi diff --git a/@ether/library/Language/AssemblyScript/check.sh b/@ether/library/Language/AssemblyScript/check.sh new file mode 100755 index 00000000..decf4df1 --- /dev/null +++ b/@ether/library/Language/AssemblyScript/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v asc >/dev/null 2>&1 diff --git a/@ether/library/Language/AssemblyScript/install.sh b/@ether/library/Language/AssemblyScript/install.sh new file mode 100755 index 00000000..03f8a46b --- /dev/null +++ b/@ether/library/Language/AssemblyScript/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# AssemblyScript - TypeScript to WebAssembly compiler +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/aspect-build/aspect-build-assemblyscript" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/aspect-build/aspect-build-assemblyscript.git "$REPO_DIR" + fi + cd "$REPO_DIR" && npm install && npm run build + exit 0 +fi +npm install -g assemblyscript diff --git a/@ether/library/Language/AssemblyScript/repl.sh b/@ether/library/Language/AssemblyScript/repl.sh new file mode 100755 index 00000000..522d57a5 --- /dev/null +++ b/@ether/library/Language/AssemblyScript/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "AssemblyScript does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/AssemblyScript/run.sh b/@ether/library/Language/AssemblyScript/run.sh new file mode 100755 index 00000000..9b4e8568 --- /dev/null +++ b/@ether/library/Language/AssemblyScript/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec asc "$1" --outFile "${1%.ts}.wasm" diff --git a/@ether/library/Language/Austral/check.sh b/@ether/library/Language/Austral/check.sh new file mode 100755 index 00000000..4aaca801 --- /dev/null +++ b/@ether/library/Language/Austral/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v austral >/dev/null 2>&1 diff --git a/@ether/library/Language/Austral/install.sh b/@ether/library/Language/Austral/install.sh new file mode 100755 index 00000000..235d9646 --- /dev/null +++ b/@ether/library/Language/Austral/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +# Austral - language with linear types +# Requires opam/OCaml to build from source +if command -v opam >/dev/null 2>&1; then + eval "$(opam env)" || true +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/austral/austral" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/austral/austral.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if ! command -v opam >/dev/null 2>&1; then + echo "opam is required to build Austral. Install OCaml/opam first." >&2 + exit 1 +fi +eval "$(opam env)" +opam install -y --deps-only . || true +make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" +sudo make install || cp austral "$HOME/.local/bin/" diff --git a/@ether/library/Language/Austral/repl.sh b/@ether/library/Language/Austral/repl.sh new file mode 100755 index 00000000..537fe283 --- /dev/null +++ b/@ether/library/Language/Austral/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Austral does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Austral/run.sh b/@ether/library/Language/Austral/run.sh new file mode 100755 index 00000000..8fea48d2 --- /dev/null +++ b/@ether/library/Language/Austral/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec austral compile "$1" diff --git a/@ether/library/Language/Avro/check.sh b/@ether/library/Language/Avro/check.sh new file mode 100755 index 00000000..e26372cb --- /dev/null +++ b/@ether/library/Language/Avro/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import avro" 2>/dev/null || command -v avro-tools >/dev/null 2>&1 diff --git a/@ether/library/Language/Avro/install.sh b/@ether/library/Language/Avro/install.sh new file mode 100755 index 00000000..984b573b --- /dev/null +++ b/@ether/library/Language/Avro/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Apache Avro - data serialization system +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/apache/avro" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/apache/avro.git "$REPO_DIR" + fi + cd "$REPO_DIR/lang/py" && pip install . + exit 0 +fi +pip install avro diff --git a/@ether/library/Language/Avro/repl.sh b/@ether/library/Language/Avro/repl.sh new file mode 100755 index 00000000..1ceaa429 --- /dev/null +++ b/@ether/library/Language/Avro/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Launching Python REPL with Avro imported..." +exec python3 -c "import avro; print('Avro loaded.'); import code; code.interact(local=dict(avro=avro))" diff --git a/@ether/library/Language/Avro/run.sh b/@ether/library/Language/Avro/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/Avro/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/B/check.sh b/@ether/library/Language/B/check.sh new file mode 100755 index 00000000..e0ef5c8f --- /dev/null +++ b/@ether/library/Language/B/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# B is a historical language; no standard tooling to check +exit 1 diff --git a/@ether/library/Language/B/install.sh b/@ether/library/Language/B/install.sh new file mode 100755 index 00000000..d988c168 --- /dev/null +++ b/@ether/library/Language/B/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# B is a historical programming language (predecessor to C). +# No standard modern compiler is widely available. +echo "B is a historical language. No standard modern tooling available." diff --git a/@ether/library/Language/B/repl.sh b/@ether/library/Language/B/repl.sh new file mode 100755 index 00000000..0736ad5a --- /dev/null +++ b/@ether/library/Language/B/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "B is a historical language. No REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/B/run.sh b/@ether/library/Language/B/run.sh new file mode 100755 index 00000000..06278c92 --- /dev/null +++ b/@ether/library/Language/B/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "B is a historical language with no standard modern compiler." >&2 +exit 1 diff --git a/@ether/library/Language/BASIC/check.sh b/@ether/library/Language/BASIC/check.sh new file mode 100755 index 00000000..7e3b918a --- /dev/null +++ b/@ether/library/Language/BASIC/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v fbc >/dev/null 2>&1 diff --git a/@ether/library/Language/BASIC/install.sh b/@ether/library/Language/BASIC/install.sh new file mode 100755 index 00000000..12931130 --- /dev/null +++ b/@ether/library/Language/BASIC/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# BASIC - FreeBASIC compiler +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/freebasic/fbc" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/freebasic/fbc.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + sudo make install || cp bin/fbc "$HOME/.local/bin/" + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install freebasic +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y freebasic +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y freebasic +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm freebasic +else + echo "No package manager found. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/BASIC/repl.sh b/@ether/library/Language/BASIC/repl.sh new file mode 100755 index 00000000..7b3d99b4 --- /dev/null +++ b/@ether/library/Language/BASIC/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "FreeBASIC does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/BASIC/run.sh b/@ether/library/Language/BASIC/run.sh new file mode 100755 index 00000000..15744176 --- /dev/null +++ b/@ether/library/Language/BASIC/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +fbc "$1" -x "${1%.bas}" && exec "./${1%.bas}" diff --git a/@ether/library/Language/BAliPhy/check.sh b/@ether/library/Language/BAliPhy/check.sh new file mode 100755 index 00000000..457ef728 --- /dev/null +++ b/@ether/library/Language/BAliPhy/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v bali-phy >/dev/null 2>&1 diff --git a/@ether/library/Language/BAliPhy/install.sh b/@ether/library/Language/BAliPhy/install.sh new file mode 100755 index 00000000..cc548428 --- /dev/null +++ b/@ether/library/Language/BAliPhy/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +# BAli-Phy - Bayesian phylogenetics and sequence alignment +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/bredelings/BAli-Phy" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/bredelings/BAli-Phy.git "$REPO_DIR" + fi + cd "$REPO_DIR" + mkdir -p build && cd build + cmake .. && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + sudo make install || cp bin/bali-phy "$HOME/.local/bin/" + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install bali-phy +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y bali-phy +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y bali-phy +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm bali-phy +else + echo "No package manager found. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/BAliPhy/repl.sh b/@ether/library/Language/BAliPhy/repl.sh new file mode 100755 index 00000000..9be0e3c8 --- /dev/null +++ b/@ether/library/Language/BAliPhy/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "BAli-Phy does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/BAliPhy/run.sh b/@ether/library/Language/BAliPhy/run.sh new file mode 100755 index 00000000..e7a64655 --- /dev/null +++ b/@ether/library/Language/BAliPhy/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec bali-phy "$1" diff --git a/@ether/library/Language/BLOG/check.sh b/@ether/library/Language/BLOG/check.sh new file mode 100755 index 00000000..7be8499c --- /dev/null +++ b/@ether/library/Language/BLOG/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/BayesianLogic/blog" +[[ -d "$REPO_DIR" ]] && command -v java >/dev/null 2>&1 diff --git a/@ether/library/Language/BLOG/install.sh b/@ether/library/Language/BLOG/install.sh new file mode 100755 index 00000000..cda89b4a --- /dev/null +++ b/@ether/library/Language/BLOG/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +# BLOG - Bayesian Logic (Java-based probabilistic programming) +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/BayesianLogic/blog" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/BayesianLogic/blog.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v java >/dev/null 2>&1; then + if [[ -f build.xml ]]; then + ant build || true + elif [[ -f pom.xml ]]; then + mvn package -DskipTests || true + elif [[ -f gradlew ]]; then + ./gradlew build || true + fi + chmod +x dblog 2>/dev/null || chmod +x blog 2>/dev/null || true +else + echo "Java is required to build BLOG." >&2; exit 1 +fi diff --git a/@ether/library/Language/BLOG/repl.sh b/@ether/library/Language/BLOG/repl.sh new file mode 100755 index 00000000..37a25edf --- /dev/null +++ b/@ether/library/Language/BLOG/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "BLOG does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/BLOG/run.sh b/@ether/library/Language/BLOG/run.sh new file mode 100755 index 00000000..f3d12813 --- /dev/null +++ b/@ether/library/Language/BLOG/run.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/BayesianLogic/blog" +if [[ -x "$REPO_DIR/dblog" ]]; then + exec "$REPO_DIR/dblog" "$1" +elif [[ -x "$REPO_DIR/blog" ]]; then + exec "$REPO_DIR/blog" "$1" +else + echo "BLOG interpreter not found. Run install.sh first." >&2; exit 1 +fi diff --git a/@ether/library/Language/BNF/check.sh b/@ether/library/Language/BNF/check.sh new file mode 100755 index 00000000..ab8d465f --- /dev/null +++ b/@ether/library/Language/BNF/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# BNF is a notation; always available +exit 0 diff --git a/@ether/library/Language/BNF/install.sh b/@ether/library/Language/BNF/install.sh new file mode 100755 index 00000000..5c2a19cf --- /dev/null +++ b/@ether/library/Language/BNF/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# BNF (Backus-Naur Form) is a notation for describing grammars, not an executable language. +echo "BNF is a notation for describing grammars. No installation required." diff --git a/@ether/library/Language/BNF/repl.sh b/@ether/library/Language/BNF/repl.sh new file mode 100755 index 00000000..23db6711 --- /dev/null +++ b/@ether/library/Language/BNF/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "BNF is a notation. No REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/BNF/run.sh b/@ether/library/Language/BNF/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/BNF/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/BQN/check.sh b/@ether/library/Language/BQN/check.sh new file mode 100755 index 00000000..97f89150 --- /dev/null +++ b/@ether/library/Language/BQN/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v bqn >/dev/null 2>&1 diff --git a/@ether/library/Language/BQN/install.sh b/@ether/library/Language/BQN/install.sh new file mode 100755 index 00000000..6659e897 --- /dev/null +++ b/@ether/library/Language/BQN/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/dzaima/CBQN" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/dzaima/CBQN.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" +sudo cp BQN /usr/local/bin/bqn || cp BQN "$HOME/.local/bin/bqn" diff --git a/@ether/library/Language/BQN/repl.sh b/@ether/library/Language/BQN/repl.sh new file mode 100755 index 00000000..95f9c498 --- /dev/null +++ b/@ether/library/Language/BQN/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec bqn diff --git a/@ether/library/Language/BQN/run.sh b/@ether/library/Language/BQN/run.sh new file mode 100755 index 00000000..be831e28 --- /dev/null +++ b/@ether/library/Language/BQN/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec bqn "$1" diff --git a/@ether/library/Language/BUGS/check.sh b/@ether/library/Language/BUGS/check.sh new file mode 100755 index 00000000..cbb73f5a --- /dev/null +++ b/@ether/library/Language/BUGS/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v julia >/dev/null 2>&1 || command -v Rscript >/dev/null 2>&1 diff --git a/@ether/library/Language/BUGS/install.sh b/@ether/library/Language/BUGS/install.sh new file mode 100755 index 00000000..e416eccc --- /dev/null +++ b/@ether/library/Language/BUGS/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# BUGS models are typically run via R (R2OpenBUGS/R2WinBUGS) or Julia (JuliaBUGS.jl) +if command -v julia >/dev/null 2>&1; then + julia -e 'using Pkg; Pkg.add("JuliaBUGS")' +elif command -v Rscript >/dev/null 2>&1; then + Rscript -e 'install.packages("R2OpenBUGS", repos="https://cran.r-project.org")' +else + echo "Install Julia or R first to use BUGS models." >&2 + exit 1 +fi diff --git a/@ether/library/Language/BUGS/repl.sh b/@ether/library/Language/BUGS/repl.sh new file mode 100755 index 00000000..12bd475e --- /dev/null +++ b/@ether/library/Language/BUGS/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v julia >/dev/null 2>&1; then + exec julia -e "using JuliaBUGS" +else + echo "BUGS does not provide a standalone REPL. Use Julia or R." >&2 + exit 1 +fi diff --git a/@ether/library/Language/BUGS/run.sh b/@ether/library/Language/BUGS/run.sh new file mode 100755 index 00000000..77e53fee --- /dev/null +++ b/@ether/library/Language/BUGS/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v julia >/dev/null 2>&1; then + exec julia -e "using JuliaBUGS; include(\"$1\")" +elif command -v Rscript >/dev/null 2>&1; then + exec Rscript "$1" +else + echo "No BUGS runtime found. Install Julia or R." >&2; exit 1 +fi diff --git a/@ether/library/Language/Ballerina/check.sh b/@ether/library/Language/Ballerina/check.sh new file mode 100755 index 00000000..84461c5f --- /dev/null +++ b/@ether/library/Language/Ballerina/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v bal >/dev/null 2>&1 || command -v ballerina >/dev/null 2>&1 diff --git a/@ether/library/Language/Ballerina/install.sh b/@ether/library/Language/Ballerina/install.sh new file mode 100755 index 00000000..23bc6049 --- /dev/null +++ b/@ether/library/Language/Ballerina/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# Ballerina - cloud-native integration language +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ballerina-platform/ballerina-lang" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ballerina-platform/ballerina-lang.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./gradlew build -x test + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install bal +elif command -v apt-get >/dev/null 2>&1; then + # Use official installer + curl -sSL https://dist.ballerina.io/downloads/latest/ballerina-linux-installer-x64.deb -o /tmp/ballerina.deb + sudo dpkg -i /tmp/ballerina.deb && rm /tmp/ballerina.deb +elif command -v dnf >/dev/null 2>&1; then + curl -sSL https://dist.ballerina.io/downloads/latest/ballerina-linux-installer-x64.rpm -o /tmp/ballerina.rpm + sudo dnf install -y /tmp/ballerina.rpm && rm /tmp/ballerina.rpm +else + echo "Download Ballerina from https://ballerina.io/downloads/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Ballerina/repl.sh b/@ether/library/Language/Ballerina/repl.sh new file mode 100755 index 00000000..7b9d16a1 --- /dev/null +++ b/@ether/library/Language/Ballerina/repl.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v bal >/dev/null 2>&1; then + exec bal shell +else + echo "Ballerina is not installed." >&2; exit 1 +fi diff --git a/@ether/library/Language/Ballerina/run.sh b/@ether/library/Language/Ballerina/run.sh new file mode 100755 index 00000000..189b5e2e --- /dev/null +++ b/@ether/library/Language/Ballerina/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v bal >/dev/null 2>&1; then + exec bal run "$1" +elif command -v ballerina >/dev/null 2>&1; then + exec ballerina run "$1" +else + echo "No Ballerina installation found." >&2; exit 1 +fi diff --git a/@ether/library/Language/Bash/check.sh b/@ether/library/Language/Bash/check.sh new file mode 100755 index 00000000..e86bb1a9 --- /dev/null +++ b/@ether/library/Language/Bash/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v bash >/dev/null 2>&1 diff --git a/@ether/library/Language/Bash/install.sh b/@ether/library/Language/Bash/install.sh new file mode 100755 index 00000000..df6531d7 --- /dev/null +++ b/@ether/library/Language/Bash/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install bash +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y bash +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y bash +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm bash +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Bash/repl.sh b/@ether/library/Language/Bash/repl.sh new file mode 100755 index 00000000..fc54e324 --- /dev/null +++ b/@ether/library/Language/Bash/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec bash --norc --noprofile diff --git a/@ether/library/Language/Bash/run.sh b/@ether/library/Language/Bash/run.sh new file mode 100755 index 00000000..0a21a0a3 --- /dev/null +++ b/@ether/library/Language/Bash/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec bash "$@" diff --git a/@ether/library/Language/BayesDB/check.sh b/@ether/library/Language/BayesDB/check.sh new file mode 100755 index 00000000..06f42600 --- /dev/null +++ b/@ether/library/Language/BayesDB/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import bayeslite" 2>/dev/null diff --git a/@ether/library/Language/BayesDB/install.sh b/@ether/library/Language/BayesDB/install.sh new file mode 100755 index 00000000..da750d84 --- /dev/null +++ b/@ether/library/Language/BayesDB/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# BayesDB - probabilistic database (bayeslite) +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/probcomp/bayeslite" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/probcomp/bayeslite.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install bayeslite diff --git a/@ether/library/Language/BayesDB/repl.sh b/@ether/library/Language/BayesDB/repl.sh new file mode 100755 index 00000000..11d4ef39 --- /dev/null +++ b/@ether/library/Language/BayesDB/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Launching Python REPL with bayeslite imported..." +exec python3 -c "import bayeslite; print('bayeslite loaded.'); import code; code.interact(local=dict(bayeslite=bayeslite))" diff --git a/@ether/library/Language/BayesDB/run.sh b/@ether/library/Language/BayesDB/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/BayesDB/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Bazel/check.sh b/@ether/library/Language/Bazel/check.sh new file mode 100755 index 00000000..9d65e79b --- /dev/null +++ b/@ether/library/Language/Bazel/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v bazel >/dev/null 2>&1 diff --git a/@ether/library/Language/Bazel/install.sh b/@ether/library/Language/Bazel/install.sh new file mode 100755 index 00000000..3aef619e --- /dev/null +++ b/@ether/library/Language/Bazel/install.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail +# Bazel - build tool by Google +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/bazelbuild/bazel" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/bazelbuild/bazel.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./compile.sh + sudo cp output/bazel /usr/local/bin/ || cp output/bazel "$HOME/.local/bin/" + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install bazel +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y apt-transport-https curl gnupg + curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor >bazel-archive-keyring.gpg + sudo mv bazel-archive-keyring.gpg /usr/share/keyrings/ + echo "deb [arch=amd64 signed-by=/usr/share/keyrings/bazel-archive-keyring.gpg] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list + sudo apt-get update && sudo apt-get install -y bazel +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y dnf-plugins-core + sudo dnf copr enable -y vbatts/bazel + sudo dnf install -y bazel +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm bazel +else + echo "No package manager found. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/Bazel/repl.sh b/@ether/library/Language/Bazel/repl.sh new file mode 100755 index 00000000..1345aaf5 --- /dev/null +++ b/@ether/library/Language/Bazel/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Bazel does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Bazel/run.sh b/@ether/library/Language/Bazel/run.sh new file mode 100755 index 00000000..0452ba32 --- /dev/null +++ b/@ether/library/Language/Bazel/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec bazel build "$1" diff --git a/@ether/library/Language/BeanMachine/check.sh b/@ether/library/Language/BeanMachine/check.sh new file mode 100755 index 00000000..2267b55f --- /dev/null +++ b/@ether/library/Language/BeanMachine/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import beanmachine" 2>/dev/null diff --git a/@ether/library/Language/BeanMachine/install.sh b/@ether/library/Language/BeanMachine/install.sh new file mode 100755 index 00000000..01c8b80b --- /dev/null +++ b/@ether/library/Language/BeanMachine/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Bean Machine - probabilistic programming (Meta) +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/facebookresearch/beanmachine" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/facebookresearch/beanmachine.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install beanmachine diff --git a/@ether/library/Language/BeanMachine/repl.sh b/@ether/library/Language/BeanMachine/repl.sh new file mode 100755 index 00000000..3e69bae1 --- /dev/null +++ b/@ether/library/Language/BeanMachine/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Launching Python REPL with Bean Machine imported..." +exec python3 -c "import beanmachine; print('Bean Machine loaded.'); import code; code.interact(local=dict(beanmachine=beanmachine))" diff --git a/@ether/library/Language/BeanMachine/run.sh b/@ether/library/Language/BeanMachine/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/BeanMachine/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Beatnik/check.sh b/@ether/library/Language/Beatnik/check.sh new file mode 100755 index 00000000..64c70040 --- /dev/null +++ b/@ether/library/Language/Beatnik/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/catseye/Beatnik" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/Beatnik/install.sh b/@ether/library/Language/Beatnik/install.sh new file mode 100755 index 00000000..1b5052c1 --- /dev/null +++ b/@ether/library/Language/Beatnik/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Beatnik - esoteric language based on Scrabble scores +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/catseye/Beatnik" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/catseye/Beatnik.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if [[ -f Makefile ]]; then + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" +fi +echo "Beatnik interpreter available at $REPO_DIR" diff --git a/@ether/library/Language/Beatnik/repl.sh b/@ether/library/Language/Beatnik/repl.sh new file mode 100755 index 00000000..2dc66b66 --- /dev/null +++ b/@ether/library/Language/Beatnik/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Beatnik does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Beatnik/run.sh b/@ether/library/Language/Beatnik/run.sh new file mode 100755 index 00000000..90db07cf --- /dev/null +++ b/@ether/library/Language/Beatnik/run.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/catseye/Beatnik" +if [[ -d "$REPO_DIR" ]]; then + # Try to find an interpreter in the repo + if [[ -f "$REPO_DIR/impl/beatnik.py" ]]; then + exec python3 "$REPO_DIR/impl/beatnik.py" "$1" + elif [[ -f "$REPO_DIR/src/beatnik" ]]; then + exec "$REPO_DIR/src/beatnik" "$1" + else + echo "Beatnik interpreter not found in $REPO_DIR." >&2; exit 1 + fi +else + echo "Beatnik is not installed. Run install.sh first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Befunge/check.sh b/@ether/library/Language/Befunge/check.sh new file mode 100755 index 00000000..053becf3 --- /dev/null +++ b/@ether/library/Language/Befunge/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v befungee >/dev/null 2>&1 || command -v bef >/dev/null 2>&1 || python3 -c "import befungee" 2>/dev/null diff --git a/@ether/library/Language/Befunge/install.sh b/@ether/library/Language/Befunge/install.sh new file mode 100755 index 00000000..e99184b6 --- /dev/null +++ b/@ether/library/Language/Befunge/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Befunge - esoteric 2D stack-based language +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/catseye/Befunge-93" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/catseye/Befunge-93.git "$REPO_DIR" + fi + cd "$REPO_DIR" + if [[ -f Makefile ]]; then + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + fi + sudo cp bin/bef /usr/local/bin/ 2>/dev/null || cp bin/bef "$HOME/.local/bin/" 2>/dev/null || true + exit 0 +fi +pip install befungee diff --git a/@ether/library/Language/Befunge/repl.sh b/@ether/library/Language/Befunge/repl.sh new file mode 100755 index 00000000..1d665693 --- /dev/null +++ b/@ether/library/Language/Befunge/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Befunge does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Befunge/run.sh b/@ether/library/Language/Befunge/run.sh new file mode 100755 index 00000000..b4286d94 --- /dev/null +++ b/@ether/library/Language/Befunge/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v befungee >/dev/null 2>&1; then + exec befungee "$1" +elif command -v bef >/dev/null 2>&1; then + exec bef "$1" +else + exec python3 -m befungee "$1" +fi diff --git a/@ether/library/Language/Beluga/check.sh b/@ether/library/Language/Beluga/check.sh new file mode 100755 index 00000000..c0f8c996 --- /dev/null +++ b/@ether/library/Language/Beluga/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v beluga >/dev/null 2>&1 diff --git a/@ether/library/Language/Beluga/install.sh b/@ether/library/Language/Beluga/install.sh new file mode 100755 index 00000000..6a46e502 --- /dev/null +++ b/@ether/library/Language/Beluga/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail +# Beluga - proof assistant for reasoning with higher-order abstract syntax +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Beluga-lang/Beluga" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Beluga-lang/Beluga.git "$REPO_DIR" + fi + cd "$REPO_DIR" + if command -v opam >/dev/null 2>&1; then + eval "$(opam env)" + opam install -y --deps-only . || true + fi + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + sudo make install || cp bin/beluga "$HOME/.local/bin/" + exit 0 +fi +# Install via opam (recommended) +if command -v opam >/dev/null 2>&1; then + eval "$(opam env)" || true + opam install -y beluga +else + echo "opam is required. Install OCaml/opam first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Beluga/repl.sh b/@ether/library/Language/Beluga/repl.sh new file mode 100755 index 00000000..cca7a1f1 --- /dev/null +++ b/@ether/library/Language/Beluga/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Beluga does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Beluga/run.sh b/@ether/library/Language/Beluga/run.sh new file mode 100755 index 00000000..78490fab --- /dev/null +++ b/@ether/library/Language/Beluga/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec beluga "$1" diff --git a/@ether/library/Language/Bend/check.sh b/@ether/library/Language/Bend/check.sh new file mode 100755 index 00000000..02bf239b --- /dev/null +++ b/@ether/library/Language/Bend/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v bend >/dev/null 2>&1 diff --git a/@ether/library/Language/Bend/install.sh b/@ether/library/Language/Bend/install.sh new file mode 100755 index 00000000..fac6ea29 --- /dev/null +++ b/@ether/library/Language/Bend/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Bend - massively parallel programming language (HigherOrderCO) +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/HigherOrderCO/Bend" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/HigherOrderCO/Bend.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + sudo cp target/release/bend /usr/local/bin/ || cp target/release/bend "$HOME/.local/bin/" + exit 0 +fi +cargo install bend-lang diff --git a/@ether/library/Language/Bend/repl.sh b/@ether/library/Language/Bend/repl.sh new file mode 100755 index 00000000..26ff12bc --- /dev/null +++ b/@ether/library/Language/Bend/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Bend does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Bend/run.sh b/@ether/library/Language/Bend/run.sh new file mode 100755 index 00000000..00de526e --- /dev/null +++ b/@ether/library/Language/Bend/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec bend run "$1" diff --git a/@ether/library/Language/Birch/check.sh b/@ether/library/Language/Birch/check.sh new file mode 100755 index 00000000..62c20cd8 --- /dev/null +++ b/@ether/library/Language/Birch/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v birch >/dev/null 2>&1 diff --git a/@ether/library/Language/Birch/install.sh b/@ether/library/Language/Birch/install.sh new file mode 100755 index 00000000..e944c81f --- /dev/null +++ b/@ether/library/Language/Birch/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +# Birch - probabilistic programming language +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/lawmurray/Birch" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/lawmurray/Birch.git "$REPO_DIR" +fi +cd "$REPO_DIR" +# Install dependencies +if [[ "$(uname)" == "Darwin" ]]; then + brew install autoconf automake libtool flex bison boost eigen libyaml +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y autoconf automake libtool flex bison libboost-all-dev libeigen3-dev libyaml-dev +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y autoconf automake libtool flex bison boost-devel eigen3-devel libyaml-devel +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm autoconf automake libtool flex bison boost eigen yaml-cpp +fi +./bootstrap && ./configure && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" +sudo make install || cp birch "$HOME/.local/bin/" diff --git a/@ether/library/Language/Birch/repl.sh b/@ether/library/Language/Birch/repl.sh new file mode 100755 index 00000000..9aec2289 --- /dev/null +++ b/@ether/library/Language/Birch/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Birch does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Birch/run.sh b/@ether/library/Language/Birch/run.sh new file mode 100755 index 00000000..ee1323c3 --- /dev/null +++ b/@ether/library/Language/Birch/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec birch "$1" diff --git a/@ether/library/Language/Bitwuzla/check.sh b/@ether/library/Language/Bitwuzla/check.sh new file mode 100755 index 00000000..ae92f0e5 --- /dev/null +++ b/@ether/library/Language/Bitwuzla/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v bitwuzla >/dev/null 2>&1 || python3 -c "import bitwuzla" 2>/dev/null diff --git a/@ether/library/Language/Bitwuzla/install.sh b/@ether/library/Language/Bitwuzla/install.sh new file mode 100755 index 00000000..ec2bf82e --- /dev/null +++ b/@ether/library/Language/Bitwuzla/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +# Bitwuzla - SMT solver for bit-vectors and arrays +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/bitwuzla/bitwuzla" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/bitwuzla/bitwuzla.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./configure.py && cd build && ninja -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + sudo ninja install || cp bin/bitwuzla "$HOME/.local/bin/" + exit 0 +fi +pip install bitwuzla diff --git a/@ether/library/Language/Bitwuzla/repl.sh b/@ether/library/Language/Bitwuzla/repl.sh new file mode 100755 index 00000000..28d621d7 --- /dev/null +++ b/@ether/library/Language/Bitwuzla/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Bitwuzla does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Bitwuzla/run.sh b/@ether/library/Language/Bitwuzla/run.sh new file mode 100755 index 00000000..3c76ae1f --- /dev/null +++ b/@ether/library/Language/Bitwuzla/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v bitwuzla >/dev/null 2>&1; then + exec bitwuzla "$1" +else + exec python3 "$1" +fi diff --git a/@ether/library/Language/Blang/check.sh b/@ether/library/Language/Blang/check.sh new file mode 100755 index 00000000..c5b3d050 --- /dev/null +++ b/@ether/library/Language/Blang/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/UBC-Stat-ML/blangSDK" +[[ -d "$REPO_DIR" ]] && command -v java >/dev/null 2>&1 diff --git a/@ether/library/Language/Blang/install.sh b/@ether/library/Language/Blang/install.sh new file mode 100755 index 00000000..76b7e803 --- /dev/null +++ b/@ether/library/Language/Blang/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Blang - Bayesian language (Java-based) +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/UBC-Stat-ML/blangSDK" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/UBC-Stat-ML/blangSDK.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v java >/dev/null 2>&1; then + ./gradlew installDist || ./setup +else + echo "Java is required to build Blang." >&2; exit 1 +fi diff --git a/@ether/library/Language/Blang/repl.sh b/@ether/library/Language/Blang/repl.sh new file mode 100755 index 00000000..67776195 --- /dev/null +++ b/@ether/library/Language/Blang/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Blang does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Blang/run.sh b/@ether/library/Language/Blang/run.sh new file mode 100755 index 00000000..97ec9086 --- /dev/null +++ b/@ether/library/Language/Blang/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/UBC-Stat-ML/blangSDK" +cd "$REPO_DIR" && exec ./gradlew run --args="$1" diff --git a/@ether/library/Language/Bluespec/check.sh b/@ether/library/Language/Bluespec/check.sh new file mode 100755 index 00000000..45428cd1 --- /dev/null +++ b/@ether/library/Language/Bluespec/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v bsc >/dev/null 2>&1 diff --git a/@ether/library/Language/Bluespec/install.sh b/@ether/library/Language/Bluespec/install.sh new file mode 100755 index 00000000..03929247 --- /dev/null +++ b/@ether/library/Language/Bluespec/install.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +# Bluespec - hardware description language (BSC compiler) +if [[ "$(uname)" == "Darwin" ]]; then + brew install bluespec || true +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y ghc libghc-regex-compat-dev libghc-syb-dev libghc-old-time-dev tcl-dev autoconf +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y ghc ghc-regex-compat-devel ghc-syb-devel tcl-devel autoconf +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm ghc tcl autoconf +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/B-Lang-org/bsc" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone --recursive https://github.com/B-Lang-org/bsc.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" +sudo make install PREFIX=/usr/local || cp inst/bin/bsc "$HOME/.local/bin/" diff --git a/@ether/library/Language/Bluespec/repl.sh b/@ether/library/Language/Bluespec/repl.sh new file mode 100755 index 00000000..8ffdeec2 --- /dev/null +++ b/@ether/library/Language/Bluespec/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Bluespec does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Bluespec/run.sh b/@ether/library/Language/Bluespec/run.sh new file mode 100755 index 00000000..9e2fadc9 --- /dev/null +++ b/@ether/library/Language/Bluespec/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec bsc -sim -g mkTb -u "$1" diff --git a/@ether/library/Language/Boolector/check.sh b/@ether/library/Language/Boolector/check.sh new file mode 100755 index 00000000..5cdf84ad --- /dev/null +++ b/@ether/library/Language/Boolector/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v boolector >/dev/null 2>&1 diff --git a/@ether/library/Language/Boolector/install.sh b/@ether/library/Language/Boolector/install.sh new file mode 100755 index 00000000..4e159dff --- /dev/null +++ b/@ether/library/Language/Boolector/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +# Boolector - SMT solver for bit-vectors and arrays +if [[ "$(uname)" == "Darwin" ]]; then + brew install cmake git || true +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y cmake build-essential +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y cmake gcc-c++ make +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm cmake base-devel +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Boolector/boolector" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Boolector/boolector.git "$REPO_DIR" +fi +cd "$REPO_DIR" +./contrib/setup-lingeling.sh +./contrib/setup-btor2tools.sh +./configure.sh && cd build && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" +sudo make install || cp bin/boolector "$HOME/.local/bin/" diff --git a/@ether/library/Language/Boolector/repl.sh b/@ether/library/Language/Boolector/repl.sh new file mode 100755 index 00000000..99b10e71 --- /dev/null +++ b/@ether/library/Language/Boolector/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Boolector does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Boolector/run.sh b/@ether/library/Language/Boolector/run.sh new file mode 100755 index 00000000..77e267ea --- /dev/null +++ b/@ether/library/Language/Boolector/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec boolector "$1" diff --git a/@ether/library/Language/Bosque/check.sh b/@ether/library/Language/Bosque/check.sh new file mode 100755 index 00000000..b777773e --- /dev/null +++ b/@ether/library/Language/Bosque/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/microsoft/BosqueLanguage" +[[ -d "$REPO_DIR" ]] && command -v node >/dev/null 2>&1 diff --git a/@ether/library/Language/Bosque/install.sh b/@ether/library/Language/Bosque/install.sh new file mode 100755 index 00000000..6e208037 --- /dev/null +++ b/@ether/library/Language/Bosque/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/microsoft/BosqueLanguage" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/microsoft/BosqueLanguage.git "$REPO_DIR" +fi +cd "$REPO_DIR" +npm install +npm run build diff --git a/@ether/library/Language/Bosque/repl.sh b/@ether/library/Language/Bosque/repl.sh new file mode 100755 index 00000000..8b67bef7 --- /dev/null +++ b/@ether/library/Language/Bosque/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Bosque does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Bosque/run.sh b/@ether/library/Language/Bosque/run.sh new file mode 100755 index 00000000..dfa7fe6d --- /dev/null +++ b/@ether/library/Language/Bosque/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/microsoft/BosqueLanguage" +exec node "$REPO_DIR/ref_impl/src/runtimes/exegen/exegen.js" "$1" diff --git a/@ether/library/Language/Brainfuck/check.sh b/@ether/library/Language/Brainfuck/check.sh new file mode 100755 index 00000000..49932873 --- /dev/null +++ b/@ether/library/Language/Brainfuck/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v bf >/dev/null 2>&1 || command -v brainfuck >/dev/null 2>&1 diff --git a/@ether/library/Language/Brainfuck/install.sh b/@ether/library/Language/Brainfuck/install.sh new file mode 100755 index 00000000..e957cfd4 --- /dev/null +++ b/@ether/library/Language/Brainfuck/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install brainfuck +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y bf +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y brainfuck +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm brainfuck +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/fabianishere/brainfuck" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/fabianishere/brainfuck.git "$REPO_DIR" + fi + cd "$REPO_DIR" + mkdir -p build && cd build + cmake .. && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + sudo make install || cp brainfuck "$HOME/.local/bin/" +fi diff --git a/@ether/library/Language/Brainfuck/repl.sh b/@ether/library/Language/Brainfuck/repl.sh new file mode 100755 index 00000000..40a73e51 --- /dev/null +++ b/@ether/library/Language/Brainfuck/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Brainfuck does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Brainfuck/run.sh b/@ether/library/Language/Brainfuck/run.sh new file mode 100755 index 00000000..6f7002dd --- /dev/null +++ b/@ether/library/Language/Brainfuck/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v bf >/dev/null 2>&1; then + exec bf "$1" +elif command -v brainfuck >/dev/null 2>&1; then + exec brainfuck "$1" +else + echo "No brainfuck interpreter found." >&2; exit 1 +fi diff --git a/@ether/library/Language/Brainloller/check.sh b/@ether/library/Language/Brainloller/check.sh new file mode 100755 index 00000000..e6513966 --- /dev/null +++ b/@ether/library/Language/Brainloller/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v python3 >/dev/null 2>&1 && python3 -c "from PIL import Image" 2>/dev/null diff --git a/@ether/library/Language/Brainloller/install.sh b/@ether/library/Language/Brainloller/install.sh new file mode 100755 index 00000000..c6fa6ae0 --- /dev/null +++ b/@ether/library/Language/Brainloller/install.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Wikipedia/brainloller" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + # Brainloller is typically implemented as a simple Python script + mkdir -p "$REPO_DIR" + cat > "$REPO_DIR/brainloller.py" << 'PYEOF' +#!/usr/bin/env python3 +"""Brainloller interpreter - reads PNG images and interprets pixel colors as Brainfuck commands.""" +import sys +try: + from PIL import Image +except ImportError: + print("Install Pillow: pip install Pillow", file=sys.stderr) + sys.exit(1) + +COMMANDS = { + (255, 0, 0): '>', (128, 0, 0): '<', + (0, 255, 0): '+', (0, 128, 0): '-', + (0, 0, 255): '.', (0, 0, 128): ',', + (255, 255, 0): '[', (128, 128, 0): ']', + (0, 255, 255): 'rotate_cw', (0, 128, 128): 'rotate_ccw', +} + +def interpret(filename): + img = Image.open(filename).convert('RGB') + w, h = img.size + x, y, dx, dy = 0, 0, 1, 0 + bf = [] + while 0 <= x < w and 0 <= y < h: + pixel = img.getpixel((x, y)) + cmd = COMMANDS.get(pixel) + if cmd == 'rotate_cw': + dx, dy = -dy, dx + elif cmd == 'rotate_ccw': + dx, dy = dy, -dx + elif cmd: + bf.append(cmd) + x += dx + y += dy + # Execute brainfuck + code = ''.join(bf) + tape = [0] * 30000 + ptr = 0 + ip = 0 + while ip < len(code): + c = code[ip] + if c == '>': ptr += 1 + elif c == '<': ptr -= 1 + elif c == '+': tape[ptr] = (tape[ptr] + 1) % 256 + elif c == '-': tape[ptr] = (tape[ptr] - 1) % 256 + elif c == '.': sys.stdout.write(chr(tape[ptr])) + elif c == ',': + ch = sys.stdin.read(1) + tape[ptr] = ord(ch) if ch else 0 + elif c == '[' and tape[ptr] == 0: + depth = 1 + while depth > 0: + ip += 1 + if code[ip] == '[': depth += 1 + elif code[ip] == ']': depth -= 1 + elif c == ']' and tape[ptr] != 0: + depth = 1 + while depth > 0: + ip -= 1 + if code[ip] == ']': depth += 1 + elif code[ip] == '[': depth -= 1 + ip += 1 + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Usage: brainloller.py ", file=sys.stderr) + sys.exit(1) + interpret(sys.argv[1]) +PYEOF +fi +pip install Pillow 2>/dev/null || pip3 install Pillow diff --git a/@ether/library/Language/Brainloller/repl.sh b/@ether/library/Language/Brainloller/repl.sh new file mode 100755 index 00000000..37c374c3 --- /dev/null +++ b/@ether/library/Language/Brainloller/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Brainloller does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Brainloller/run.sh b/@ether/library/Language/Brainloller/run.sh new file mode 100755 index 00000000..ac462025 --- /dev/null +++ b/@ether/library/Language/Brainloller/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Wikipedia/brainloller" +exec python3 "$REPO_DIR/brainloller.py" "$1" diff --git a/@ether/library/Language/Bun/check.sh b/@ether/library/Language/Bun/check.sh new file mode 100755 index 00000000..bea9c718 --- /dev/null +++ b/@ether/library/Language/Bun/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v bun >/dev/null 2>&1 diff --git a/@ether/library/Language/Bun/install.sh b/@ether/library/Language/Bun/install.sh new file mode 100755 index 00000000..ca5215c9 --- /dev/null +++ b/@ether/library/Language/Bun/install.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install oven-sh/bun/bun +else + curl -fsSL https://bun.sh/install | bash +fi diff --git a/@ether/library/Language/Bun/repl.sh b/@ether/library/Language/Bun/repl.sh new file mode 100755 index 00000000..5c7cb3f2 --- /dev/null +++ b/@ether/library/Language/Bun/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec bun repl diff --git a/@ether/library/Language/Bun/run.sh b/@ether/library/Language/Bun/run.sh new file mode 100755 index 00000000..7e3d2529 --- /dev/null +++ b/@ether/library/Language/Bun/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec bun run "$@" diff --git a/@ether/library/Language/C/check.sh b/@ether/library/Language/C/check.sh new file mode 100755 index 00000000..3d14ad3d --- /dev/null +++ b/@ether/library/Language/C/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v gcc >/dev/null 2>&1 || command -v cc >/dev/null 2>&1 diff --git a/@ether/library/Language/C/install.sh b/@ether/library/Language/C/install.sh new file mode 100755 index 00000000..d7fd982d --- /dev/null +++ b/@ether/library/Language/C/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + xcode-select --install 2>/dev/null || true +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gcc build-essential +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gcc make +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gcc make +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/C/packages.sh b/@ether/library/Language/C/packages.sh new file mode 100755 index 00000000..3b75bc12 --- /dev/null +++ b/@ether/library/Language/C/packages.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRIES=( + "https://conan.io/center" + "https://vcpkg.io/en/packages" +) + +usage() { + echo "C Package Registries:" + for url in "${REGISTRIES[@]}"; do echo " $url"; done + echo + echo "Usage: packages.sh {search|info|install} " +} + +cmd_search() { + local q="$1" + echo "https://conan.io/center?search=$q" + echo "https://vcpkg.io/en/packages?query=$q" +} + +cmd_info() { + local pkg="$1" + echo "https://conan.io/center/recipes/$pkg" + echo "https://vcpkg.io/en/package/$pkg" +} + +cmd_install() { + local pkg="$1" + if command -v conan &>/dev/null; then + echo "Installing via Conan..." + conan install "$pkg" + elif command -v vcpkg &>/dev/null; then + echo "Installing via vcpkg..." + vcpkg install "$pkg" + else + echo "No package manager found. Install manually:" + echo " Conan: https://conan.io/center/recipes/$pkg" + echo " vcpkg: https://vcpkg.io/en/package/$pkg" + fi +} + +case "${1:-}" in + search) shift; cmd_search "$1" ;; + info) shift; cmd_info "$1" ;; + install) shift; cmd_install "$1" ;; + *) usage ;; +esac diff --git a/@ether/library/Language/C/repl.sh b/@ether/library/Language/C/repl.sh new file mode 100755 index 00000000..355a0064 --- /dev/null +++ b/@ether/library/Language/C/repl.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v cling >/dev/null 2>&1; then + exec cling "$@" +else + echo "No C REPL found." + echo "Install cling: https://github.com/root-project/cling" + echo "Alternative: use 'tcc -run' for quick script execution." + exit 1 +fi diff --git a/@ether/library/Language/C/run.sh b/@ether/library/Language/C/run.sh new file mode 100755 index 00000000..af06c175 --- /dev/null +++ b/@ether/library/Language/C/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +out="/tmp/c_out_$$" +gcc "$file" -o "$out" && "$out" +rm -f "$out" diff --git a/@ether/library/Language/CLU/check.sh b/@ether/library/Language/CLU/check.sh new file mode 100755 index 00000000..a2441764 --- /dev/null +++ b/@ether/library/Language/CLU/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/nbuwe/pclu" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/CLU/install.sh b/@ether/library/Language/CLU/install.sh new file mode 100755 index 00000000..e8c28ecb --- /dev/null +++ b/@ether/library/Language/CLU/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# CLU is a historical language by Barbara Liskov. PCLU is a portable implementation. +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/nbuwe/pclu" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/nbuwe/pclu.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make || echo "CLU build may require additional configuration." >&2 diff --git a/@ether/library/Language/CLU/repl.sh b/@ether/library/Language/CLU/repl.sh new file mode 100755 index 00000000..4b1d461a --- /dev/null +++ b/@ether/library/Language/CLU/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CLU does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/CLU/run.sh b/@ether/library/Language/CLU/run.sh new file mode 100755 index 00000000..5cfbbd22 --- /dev/null +++ b/@ether/library/Language/CLU/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/nbuwe/pclu" +exec "$REPO_DIR/bin/pclu" "$1" diff --git a/@ether/library/Language/CMake/check.sh b/@ether/library/Language/CMake/check.sh new file mode 100755 index 00000000..5a8b2c14 --- /dev/null +++ b/@ether/library/Language/CMake/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v cmake >/dev/null 2>&1 diff --git a/@ether/library/Language/CMake/install.sh b/@ether/library/Language/CMake/install.sh new file mode 100755 index 00000000..17ea8167 --- /dev/null +++ b/@ether/library/Language/CMake/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +# CMake +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing CMake from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Kitware/CMake" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Kitware/CMake.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./bootstrap --prefix=/usr/local + make -j"$(nproc)" + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install cmake +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y cmake +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y cmake +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm cmake +else + echo "Unsupported package manager. Download from https://cmake.org/download/" >&2; exit 1 +fi diff --git a/@ether/library/Language/CMake/packages.sh b/@ether/library/Language/CMake/packages.sh new file mode 100755 index 00000000..4fd3e56c --- /dev/null +++ b/@ether/library/Language/CMake/packages.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CMake is a build system, not a language with packages." +echo "For C/C++ packages, use vcpkg or Conan:" +echo " https://vcpkg.io | https://conan.io" diff --git a/@ether/library/Language/CMake/repl.sh b/@ether/library/Language/CMake/repl.sh new file mode 100755 index 00000000..a7defc0b --- /dev/null +++ b/@ether/library/Language/CMake/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CMake does not have an interactive REPL. Use: cmake -P " diff --git a/@ether/library/Language/CMake/run.sh b/@ether/library/Language/CMake/run.sh new file mode 100755 index 00000000..1a5aec45 --- /dev/null +++ b/@ether/library/Language/CMake/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cmake "$@" diff --git a/@ether/library/Language/COBOL/check.sh b/@ether/library/Language/COBOL/check.sh new file mode 100755 index 00000000..3e7a4c41 --- /dev/null +++ b/@ether/library/Language/COBOL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v cobc >/dev/null 2>&1 diff --git a/@ether/library/Language/COBOL/install.sh b/@ether/library/Language/COBOL/install.sh new file mode 100755 index 00000000..dc095dc9 --- /dev/null +++ b/@ether/library/Language/COBOL/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install gnucobol +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gnucobol +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gnucobol +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gnucobol +else + echo "Unsupported package manager. Install GnuCOBOL manually." >&2; exit 1 +fi diff --git a/@ether/library/Language/COBOL/repl.sh b/@ether/library/Language/COBOL/repl.sh new file mode 100755 index 00000000..bcf432c0 --- /dev/null +++ b/@ether/library/Language/COBOL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "COBOL does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/COBOL/run.sh b/@ether/library/Language/COBOL/run.sh new file mode 100755 index 00000000..7f22c9e4 --- /dev/null +++ b/@ether/library/Language/COBOL/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +OUT="/tmp/cobol_out_$$" +cobc -x -o "$OUT" "$1" && "$OUT" +rm -f "$OUT" diff --git a/@ether/library/Language/CPlusPlus/check.sh b/@ether/library/Language/CPlusPlus/check.sh new file mode 100755 index 00000000..2902d821 --- /dev/null +++ b/@ether/library/Language/CPlusPlus/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v g++ >/dev/null 2>&1 || command -v c++ >/dev/null 2>&1 diff --git a/@ether/library/Language/CPlusPlus/install.sh b/@ether/library/Language/CPlusPlus/install.sh new file mode 100755 index 00000000..bac98aee --- /dev/null +++ b/@ether/library/Language/CPlusPlus/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + xcode-select --install 2>/dev/null || true +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y g++ build-essential +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gcc-c++ make +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gcc make +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/CPlusPlus/packages.sh b/@ether/library/Language/CPlusPlus/packages.sh new file mode 100755 index 00000000..3026e667 --- /dev/null +++ b/@ether/library/Language/CPlusPlus/packages.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRIES=( + "https://conan.io/center" + "https://vcpkg.io/en/packages" +) + +usage() { + echo "C++ Package Registries:" + for url in "${REGISTRIES[@]}"; do echo " $url"; done + echo + echo "Usage: packages.sh {search|info|install} " +} + +cmd_search() { + local q="$1" + echo "https://conan.io/center?search=$q" + echo "https://vcpkg.io/en/packages?query=$q" +} + +cmd_info() { + local pkg="$1" + echo "https://conan.io/center/recipes/$pkg" + echo "https://vcpkg.io/en/package/$pkg" +} + +cmd_install() { + local pkg="$1" + if command -v conan &>/dev/null; then + echo "Installing via Conan..." + conan install "$pkg" + elif command -v vcpkg &>/dev/null; then + echo "Installing via vcpkg..." + vcpkg install "$pkg" + else + echo "No package manager found. Install manually:" + echo " Conan: https://conan.io/center/recipes/$pkg" + echo " vcpkg: https://vcpkg.io/en/package/$pkg" + fi +} + +case "${1:-}" in + search) shift; cmd_search "$1" ;; + info) shift; cmd_info "$1" ;; + install) shift; cmd_install "$1" ;; + *) usage ;; +esac diff --git a/@ether/library/Language/CPlusPlus/repl.sh b/@ether/library/Language/CPlusPlus/repl.sh new file mode 100755 index 00000000..7b344175 --- /dev/null +++ b/@ether/library/Language/CPlusPlus/repl.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v cling >/dev/null 2>&1; then + exec cling "$@" +else + echo "No C++ REPL found." + echo "Install cling: https://github.com/root-project/cling" + exit 1 +fi diff --git a/@ether/library/Language/CPlusPlus/run.sh b/@ether/library/Language/CPlusPlus/run.sh new file mode 100755 index 00000000..a3c2ac76 --- /dev/null +++ b/@ether/library/Language/CPlusPlus/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +out="/tmp/cpp_out_$$" +g++ "$file" -o "$out" && "$out" +rm -f "$out" diff --git a/@ether/library/Language/CSS/check.sh b/@ether/library/Language/CSS/check.sh new file mode 100755 index 00000000..2bde7819 --- /dev/null +++ b/@ether/library/Language/CSS/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# CSS is always available as a data format. +exit 0 diff --git a/@ether/library/Language/CSS/install.sh b/@ether/library/Language/CSS/install.sh new file mode 100755 index 00000000..a470eee6 --- /dev/null +++ b/@ether/library/Language/CSS/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# CSS is a stylesheet language interpreted by web browsers. No installation needed. +exit 0 diff --git a/@ether/library/Language/CSS/repl.sh b/@ether/library/Language/CSS/repl.sh new file mode 100755 index 00000000..cb48b08a --- /dev/null +++ b/@ether/library/Language/CSS/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CSS is a stylesheet language and does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/CSS/run.sh b/@ether/library/Language/CSS/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/CSS/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/CSV/check.sh b/@ether/library/Language/CSV/check.sh new file mode 100755 index 00000000..e32babbd --- /dev/null +++ b/@ether/library/Language/CSV/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# CSV is always available as a data format. +exit 0 diff --git a/@ether/library/Language/CSV/install.sh b/@ether/library/Language/CSV/install.sh new file mode 100755 index 00000000..ff461374 --- /dev/null +++ b/@ether/library/Language/CSV/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# CSV is a data format. No installation needed. +exit 0 diff --git a/@ether/library/Language/CSV/repl.sh b/@ether/library/Language/CSV/repl.sh new file mode 100755 index 00000000..f2c9fd1c --- /dev/null +++ b/@ether/library/Language/CSV/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CSV is a data format and does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/CSV/run.sh b/@ether/library/Language/CSV/run.sh new file mode 100755 index 00000000..23d2abc1 --- /dev/null +++ b/@ether/library/Language/CSV/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v column >/dev/null 2>&1; then + exec column -s, -t "$1" +else + exec cat "$1" +fi diff --git a/@ether/library/Language/CSharp/check.sh b/@ether/library/Language/CSharp/check.sh new file mode 100755 index 00000000..b4cea5bf --- /dev/null +++ b/@ether/library/Language/CSharp/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v dotnet >/dev/null 2>&1 diff --git a/@ether/library/Language/CSharp/install.sh b/@ether/library/Language/CSharp/install.sh new file mode 100755 index 00000000..af30c29e --- /dev/null +++ b/@ether/library/Language/CSharp/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official install: https://dotnet.microsoft.com/en-us/download +if [[ "$(uname)" == "Darwin" ]]; then + brew install dotnet +else + # Use Microsoft's official install script to get latest LTS + curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh + chmod +x /tmp/dotnet-install.sh + /tmp/dotnet-install.sh --channel LTS + rm -f /tmp/dotnet-install.sh + # Add to PATH if not already there + if ! grep -q '.dotnet' "$HOME/.profile" 2>/dev/null; then + echo 'export DOTNET_ROOT=$HOME/.dotnet' >> "$HOME/.profile" + echo 'export PATH=$PATH:$DOTNET_ROOT:$DOTNET_ROOT/tools' >> "$HOME/.profile" + fi + export DOTNET_ROOT="$HOME/.dotnet" + export PATH="$PATH:$DOTNET_ROOT:$DOTNET_ROOT/tools" +fi diff --git a/@ether/library/Language/CSharp/packages.sh b/@ether/library/Language/CSharp/packages.sh new file mode 100755 index 00000000..47f93220 --- /dev/null +++ b/@ether/library/Language/CSharp/packages.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="C#" +REGISTRIES=( + "NuGet: https://www.nuget.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v dotnet &>/dev/null; then + dotnet package search "$@" 2>/dev/null || echo "Visit: https://www.nuget.org/packages?q=$1" + else + echo "Visit: https://www.nuget.org/packages?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://www.nuget.org/packages/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + dotnet add package "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/CSharp/repl.sh b/@ether/library/Language/CSharp/repl.sh new file mode 100755 index 00000000..4f3fb367 --- /dev/null +++ b/@ether/library/Language/CSharp/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec dotnet csharp 2>/dev/null || exec dotnet csi 2>/dev/null || { echo "C# interactive not available" >&2; exit 1; } diff --git a/@ether/library/Language/CSharp/run.sh b/@ether/library/Language/CSharp/run.sh new file mode 100755 index 00000000..f8d63377 --- /dev/null +++ b/@ether/library/Language/CSharp/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +if [[ -d "$file" ]]; then + cd "$file" && dotnet run +else + dotnet script "$file" 2>/dev/null || dotnet-script "$file" 2>/dev/null || { echo "Install dotnet-script for single file execution" >&2; exit 1; } +fi diff --git a/@ether/library/Language/CUDA/check.sh b/@ether/library/Language/CUDA/check.sh new file mode 100755 index 00000000..d41a5b7b --- /dev/null +++ b/@ether/library/Language/CUDA/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nvcc >/dev/null 2>&1 diff --git a/@ether/library/Language/CUDA/install.sh b/@ether/library/Language/CUDA/install.sh new file mode 100755 index 00000000..59190225 --- /dev/null +++ b/@ether/library/Language/CUDA/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + echo "CUDA is not supported on macOS. Use NVIDIA GPU on Linux." >&2; exit 1 +elif command -v apt-get >/dev/null 2>&1; then + # Follow NVIDIA official instructions for Ubuntu/Debian + sudo apt-get update && sudo apt-get install -y nvidia-cuda-toolkit +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y cuda +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm cuda +else + echo "Unsupported platform. See https://developer.nvidia.com/cuda-downloads" >&2; exit 1 +fi diff --git a/@ether/library/Language/CUDA/repl.sh b/@ether/library/Language/CUDA/repl.sh new file mode 100755 index 00000000..e16e5a5d --- /dev/null +++ b/@ether/library/Language/CUDA/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CUDA does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/CUDA/run.sh b/@ether/library/Language/CUDA/run.sh new file mode 100755 index 00000000..f6866dd4 --- /dev/null +++ b/@ether/library/Language/CUDA/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +OUT="/tmp/cuda_out_$$" +nvcc "$1" -o "$OUT" && "$OUT" +rm -f "$OUT" diff --git a/@ether/library/Language/CUE/check.sh b/@ether/library/Language/CUE/check.sh new file mode 100755 index 00000000..45730471 --- /dev/null +++ b/@ether/library/Language/CUE/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v cue >/dev/null 2>&1 diff --git a/@ether/library/Language/CUE/install.sh b/@ether/library/Language/CUE/install.sh new file mode 100755 index 00000000..7aa50b20 --- /dev/null +++ b/@ether/library/Language/CUE/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install cue-lang/tap/cue +elif command -v go >/dev/null 2>&1; then + go install cuelang.org/go/cmd/cue@latest +else + # Download binary release + OS="$(uname -s | tr '[:upper:]' '[:lower:]')" + ARCH="$(uname -m)" + case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64|arm64) ARCH="arm64" ;; + esac + VERSION=$(curl -fsSL https://api.github.com/repos/cue-lang/cue/releases/latest | grep tag_name | cut -d'"' -f4) + curl -fsSL "https://github.com/cue-lang/cue/releases/download/${VERSION}/cue_${VERSION}_${OS}_${ARCH}.tar.gz" | \ + sudo tar -xz -C /usr/local/bin cue +fi diff --git a/@ether/library/Language/CUE/repl.sh b/@ether/library/Language/CUE/repl.sh new file mode 100755 index 00000000..613fa1d9 --- /dev/null +++ b/@ether/library/Language/CUE/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CUE does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/CUE/run.sh b/@ether/library/Language/CUE/run.sh new file mode 100755 index 00000000..c33f993e --- /dev/null +++ b/@ether/library/Language/CUE/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cue eval "$1" diff --git a/@ether/library/Language/CVC5/check.sh b/@ether/library/Language/CVC5/check.sh new file mode 100755 index 00000000..828962f2 --- /dev/null +++ b/@ether/library/Language/CVC5/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v cvc5 >/dev/null 2>&1 || python3 -c "import cvc5" 2>/dev/null diff --git a/@ether/library/Language/CVC5/install.sh b/@ether/library/Language/CVC5/install.sh new file mode 100755 index 00000000..14d1b44c --- /dev/null +++ b/@ether/library/Language/CVC5/install.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install cvc5 || { + pip install cvc5 || pip3 install cvc5 + } +elif command -v pip3 >/dev/null 2>&1; then + pip3 install cvc5 +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/cvc5/cvc5" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/cvc5/cvc5.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./configure.sh production --auto-download + cd build + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + sudo make install +fi diff --git a/@ether/library/Language/CVC5/repl.sh b/@ether/library/Language/CVC5/repl.sh new file mode 100755 index 00000000..03f9aceb --- /dev/null +++ b/@ether/library/Language/CVC5/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v cvc5 >/dev/null 2>&1; then + exec cvc5 --interactive +else + echo "CVC5 binary not found. Install cvc5 for interactive mode." >&2 + exit 1 +fi diff --git a/@ether/library/Language/CVC5/run.sh b/@ether/library/Language/CVC5/run.sh new file mode 100755 index 00000000..5bbcceb8 --- /dev/null +++ b/@ether/library/Language/CVC5/run.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v cvc5 >/dev/null 2>&1; then + exec cvc5 "$1" +else + exec python3 -c " +import cvc5 +import sys +with open(sys.argv[1]) as f: + print(f.read()) +" "$1" +fi diff --git a/@ether/library/Language/CaDiCaL/check.sh b/@ether/library/Language/CaDiCaL/check.sh new file mode 100755 index 00000000..83bc29f2 --- /dev/null +++ b/@ether/library/Language/CaDiCaL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v cadical >/dev/null 2>&1 diff --git a/@ether/library/Language/CaDiCaL/install.sh b/@ether/library/Language/CaDiCaL/install.sh new file mode 100755 index 00000000..25ea8d80 --- /dev/null +++ b/@ether/library/Language/CaDiCaL/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/arminbiere/cadical" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/arminbiere/cadical.git "$REPO_DIR" +fi +cd "$REPO_DIR" +./configure && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" +sudo cp build/cadical /usr/local/bin/ || cp build/cadical "$HOME/.local/bin/" diff --git a/@ether/library/Language/CaDiCaL/repl.sh b/@ether/library/Language/CaDiCaL/repl.sh new file mode 100755 index 00000000..48ac1c57 --- /dev/null +++ b/@ether/library/Language/CaDiCaL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CaDiCaL is a SAT solver and does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/CaDiCaL/run.sh b/@ether/library/Language/CaDiCaL/run.sh new file mode 100755 index 00000000..239407bb --- /dev/null +++ b/@ether/library/Language/CaDiCaL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cadical "$1" diff --git a/@ether/library/Language/Cadence/check.sh b/@ether/library/Language/Cadence/check.sh new file mode 100755 index 00000000..7ed8202b --- /dev/null +++ b/@ether/library/Language/Cadence/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v flow >/dev/null 2>&1 diff --git a/@ether/library/Language/Cadence/install.sh b/@ether/library/Language/Cadence/install.sh new file mode 100755 index 00000000..f6d36aee --- /dev/null +++ b/@ether/library/Language/Cadence/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Cadence: Flow blockchain smart contract language - https://cadence-lang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/onflow/cadence" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/onflow/cadence.git "$REPO_DIR" + fi + cd "$REPO_DIR" && go build ./... + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install flow-cli +else + sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" +fi diff --git a/@ether/library/Language/Cadence/packages.sh b/@ether/library/Language/Cadence/packages.sh new file mode 100755 index 00000000..6c01a41f --- /dev/null +++ b/@ether/library/Language/Cadence/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Cadence" +REGISTRIES=( + "Flow GitHub: https://github.com/onflow" + "FlowDiver: https://flowdiver.io" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Note: Cadence uses Flow's dependency management via flow.json." + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://github.com/search?q=cadence+$1&type=repositories" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://github.com/search?q=cadence+$1&type=repositories" + echo "Check flow.json in the repository for contract details." + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to flow.json contracts section:" + echo " \"$1\": { \"source\": \"./contracts/$1.cdc\", \"aliases\": {} }" + echo "" + echo "Or install via Flow CLI:" + echo " flow dependencies install" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Cadence/repl.sh b/@ether/library/Language/Cadence/repl.sh new file mode 100755 index 00000000..66fa208c --- /dev/null +++ b/@ether/library/Language/Cadence/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec flow cadence diff --git a/@ether/library/Language/Cadence/run.sh b/@ether/library/Language/Cadence/run.sh new file mode 100755 index 00000000..f1be8aab --- /dev/null +++ b/@ether/library/Language/Cadence/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec flow cadence "$@" diff --git a/@ether/library/Language/Cairo/check.sh b/@ether/library/Language/Cairo/check.sh new file mode 100755 index 00000000..8e69f838 --- /dev/null +++ b/@ether/library/Language/Cairo/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v scarb >/dev/null 2>&1 || command -v cairo-compile >/dev/null 2>&1 diff --git a/@ether/library/Language/Cairo/install.sh b/@ether/library/Language/Cairo/install.sh new file mode 100755 index 00000000..675eb05f --- /dev/null +++ b/@ether/library/Language/Cairo/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +# Cairo: StarkNet smart contract language - https://www.cairo-lang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/starkware-libs/cairo" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/starkware-libs/cairo.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + exit 0 +fi +# Install Scarb (Cairo package manager and build tool) +if [[ "$(uname)" == "Darwin" ]]; then + brew install scarb || curl -fsSL https://docs.swmansion.com/scarb/install.sh | sh +elif command -v curl >/dev/null 2>&1; then + curl -fsSL https://docs.swmansion.com/scarb/install.sh | sh +else + # Fallback: pip install cairo-lang + pip3 install cairo-lang +fi diff --git a/@ether/library/Language/Cairo/packages.sh b/@ether/library/Language/Cairo/packages.sh new file mode 100755 index 00000000..1f7d0759 --- /dev/null +++ b/@ether/library/Language/Cairo/packages.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Cairo" +REGISTRIES=( + "GitHub (primary): https://github.com/search?q=language%3Acairo&type=repositories" + "scarbs.xyz (emerging): https://scarbs.xyz" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Note: Cairo uses Scarb for dependency management. Most packages are distributed via GitHub." + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://github.com/search?q=language%3Acairo+$1&type=repositories" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://github.com/search?q=language%3Acairo+$1&type=repositories" + echo "Check Scarb.toml in the repository for version and dependency info." + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to Scarb.toml [dependencies]:" + echo " $1 = { git = \"https://github.com/OWNER/$1\" }" + echo "" + echo "Then run: scarb build" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Cairo/repl.sh b/@ether/library/Language/Cairo/repl.sh new file mode 100755 index 00000000..2859d81a --- /dev/null +++ b/@ether/library/Language/Cairo/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Cairo does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Cairo/run.sh b/@ether/library/Language/Cairo/run.sh new file mode 100755 index 00000000..54c4d1a1 --- /dev/null +++ b/@ether/library/Language/Cairo/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v scarb >/dev/null 2>&1; then + exec scarb build "$@" +else + exec cairo-run "$@" +fi diff --git a/@ether/library/Language/Caledon/check.sh b/@ether/library/Language/Caledon/check.sh new file mode 100755 index 00000000..a18ed250 --- /dev/null +++ b/@ether/library/Language/Caledon/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mmirman/caledon" +[[ -d "$REPO_DIR" ]] && command -v cabal >/dev/null 2>&1 diff --git a/@ether/library/Language/Caledon/install.sh b/@ether/library/Language/Caledon/install.sh new file mode 100755 index 00000000..2fe7577b --- /dev/null +++ b/@ether/library/Language/Caledon/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mmirman/caledon" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/mmirman/caledon.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v cabal >/dev/null 2>&1; then + cabal update && cabal build +elif command -v stack >/dev/null 2>&1; then + stack build +else + echo "Install GHC/cabal or stack first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Caledon/repl.sh b/@ether/library/Language/Caledon/repl.sh new file mode 100755 index 00000000..63492549 --- /dev/null +++ b/@ether/library/Language/Caledon/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Caledon does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Caledon/run.sh b/@ether/library/Language/Caledon/run.sh new file mode 100755 index 00000000..38e92d9a --- /dev/null +++ b/@ether/library/Language/Caledon/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mmirman/caledon" +cd "$REPO_DIR" +cabal run caledon -- "$1" diff --git a/@ether/library/Language/Caml/check.sh b/@ether/library/Language/Caml/check.sh new file mode 100755 index 00000000..7889fad8 --- /dev/null +++ b/@ether/library/Language/Caml/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v ocaml >/dev/null 2>&1 diff --git a/@ether/library/Language/Caml/install.sh b/@ether/library/Language/Caml/install.sh new file mode 100755 index 00000000..bc060aba --- /dev/null +++ b/@ether/library/Language/Caml/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Caml Light is the predecessor of OCaml. Install OCaml which includes backward compatibility. +if [[ "$(uname)" == "Darwin" ]]; then + brew install ocaml +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y ocaml +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y ocaml +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm ocaml +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Caml/repl.sh b/@ether/library/Language/Caml/repl.sh new file mode 100755 index 00000000..de5da26a --- /dev/null +++ b/@ether/library/Language/Caml/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ocaml diff --git a/@ether/library/Language/Caml/run.sh b/@ether/library/Language/Caml/run.sh new file mode 100755 index 00000000..d229e2f2 --- /dev/null +++ b/@ether/library/Language/Caml/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ocaml "$1" diff --git a/@ether/library/Language/CapnProto/check.sh b/@ether/library/Language/CapnProto/check.sh new file mode 100755 index 00000000..1f3a94d9 --- /dev/null +++ b/@ether/library/Language/CapnProto/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v capnp >/dev/null 2>&1 diff --git a/@ether/library/Language/CapnProto/install.sh b/@ether/library/Language/CapnProto/install.sh new file mode 100755 index 00000000..14a1ae99 --- /dev/null +++ b/@ether/library/Language/CapnProto/install.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install capnp +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y capnproto libcapnp-dev +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y capnproto capnproto-devel +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm capnproto +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/capnproto/capnproto" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/capnproto/capnproto.git "$REPO_DIR" + fi + cd "$REPO_DIR/c++" + autoreconf -i && ./configure && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + sudo make install +fi diff --git a/@ether/library/Language/CapnProto/repl.sh b/@ether/library/Language/CapnProto/repl.sh new file mode 100755 index 00000000..aca4d1be --- /dev/null +++ b/@ether/library/Language/CapnProto/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Cap'n Proto does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/CapnProto/run.sh b/@ether/library/Language/CapnProto/run.sh new file mode 100755 index 00000000..336bbe52 --- /dev/null +++ b/@ether/library/Language/CapnProto/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec capnp compile -o- "$1" diff --git a/@ether/library/Language/Carbon/check.sh b/@ether/library/Language/Carbon/check.sh new file mode 100755 index 00000000..b20d5304 --- /dev/null +++ b/@ether/library/Language/Carbon/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/carbon-language/carbon-lang" +[[ -d "$REPO_DIR" ]] && command -v bazel >/dev/null 2>&1 diff --git a/@ether/library/Language/Carbon/install.sh b/@ether/library/Language/Carbon/install.sh new file mode 100755 index 00000000..1b953b14 --- /dev/null +++ b/@ether/library/Language/Carbon/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/carbon-language/carbon-lang" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/carbon-language/carbon-lang.git "$REPO_DIR" +fi +# Carbon requires Bazel and Clang/LLVM +if ! command -v bazel >/dev/null 2>&1; then + echo "Bazel is required. Install it first: https://bazel.build/install" >&2 + exit 1 +fi +cd "$REPO_DIR" +bazel build //explorer diff --git a/@ether/library/Language/Carbon/repl.sh b/@ether/library/Language/Carbon/repl.sh new file mode 100755 index 00000000..fe12cb66 --- /dev/null +++ b/@ether/library/Language/Carbon/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Carbon does not currently provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Carbon/run.sh b/@ether/library/Language/Carbon/run.sh new file mode 100755 index 00000000..2b2a23d8 --- /dev/null +++ b/@ether/library/Language/Carbon/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/carbon-language/carbon-lang" +cd "$REPO_DIR" +bazel run //explorer -- "$1" diff --git a/@ether/library/Language/Carp/check.sh b/@ether/library/Language/Carp/check.sh new file mode 100755 index 00000000..7f66db58 --- /dev/null +++ b/@ether/library/Language/Carp/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v carp >/dev/null 2>&1 diff --git a/@ether/library/Language/Carp/install.sh b/@ether/library/Language/Carp/install.sh new file mode 100755 index 00000000..834b4b2b --- /dev/null +++ b/@ether/library/Language/Carp/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/carp-lang/Carp" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/carp-lang/Carp.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v stack >/dev/null 2>&1; then + stack build && stack install +elif command -v cabal >/dev/null 2>&1; then + cabal update && cabal build && cabal install +else + echo "Install Haskell Stack or cabal first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Carp/repl.sh b/@ether/library/Language/Carp/repl.sh new file mode 100755 index 00000000..b7aa75b5 --- /dev/null +++ b/@ether/library/Language/Carp/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec carp diff --git a/@ether/library/Language/Carp/run.sh b/@ether/library/Language/Carp/run.sh new file mode 100755 index 00000000..a4b36a21 --- /dev/null +++ b/@ether/library/Language/Carp/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec carp -x "$1" diff --git a/@ether/library/Language/Cat/check.sh b/@ether/library/Language/Cat/check.sh new file mode 100755 index 00000000..8300b529 --- /dev/null +++ b/@ether/library/Language/Cat/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/cdiggins/cat-language" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/Cat/install.sh b/@ether/library/Language/Cat/install.sh new file mode 100755 index 00000000..db62bf66 --- /dev/null +++ b/@ether/library/Language/Cat/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/cdiggins/cat-language" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/cdiggins/cat-language.git "$REPO_DIR" +fi +echo "Cat language cloned to $REPO_DIR. It requires .NET to build." +if command -v dotnet >/dev/null 2>&1; then + cd "$REPO_DIR" + dotnet build || true +fi diff --git a/@ether/library/Language/Cat/repl.sh b/@ether/library/Language/Cat/repl.sh new file mode 100755 index 00000000..029670d4 --- /dev/null +++ b/@ether/library/Language/Cat/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Cat does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Cat/run.sh b/@ether/library/Language/Cat/run.sh new file mode 100755 index 00000000..1c6fab1d --- /dev/null +++ b/@ether/library/Language/Cat/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/cdiggins/cat-language" +cd "$REPO_DIR" +dotnet run -- "$1" diff --git a/@ether/library/Language/Catala/check.sh b/@ether/library/Language/Catala/check.sh new file mode 100755 index 00000000..e035371c --- /dev/null +++ b/@ether/library/Language/Catala/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v catala >/dev/null 2>&1 diff --git a/@ether/library/Language/Catala/install.sh b/@ether/library/Language/Catala/install.sh new file mode 100755 index 00000000..47b3fe95 --- /dev/null +++ b/@ether/library/Language/Catala/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v opam >/dev/null 2>&1; then + opam install catala -y +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/CatalaLang/catala" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/CatalaLang/catala.git "$REPO_DIR" + fi + cd "$REPO_DIR" + make build + sudo cp _build/default/compiler/catala.exe /usr/local/bin/catala || \ + cp _build/default/compiler/catala.exe "$HOME/.local/bin/catala" +fi diff --git a/@ether/library/Language/Catala/repl.sh b/@ether/library/Language/Catala/repl.sh new file mode 100755 index 00000000..d7e0cbc7 --- /dev/null +++ b/@ether/library/Language/Catala/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Catala does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Catala/run.sh b/@ether/library/Language/Catala/run.sh new file mode 100755 index 00000000..6e0fc550 --- /dev/null +++ b/@ether/library/Language/Catala/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec catala interpret "$1" diff --git a/@ether/library/Language/Categorica/check.sh b/@ether/library/Language/Categorica/check.sh new file mode 100755 index 00000000..4b61e16f --- /dev/null +++ b/@ether/library/Language/Categorica/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/JonathanGorard/Categorica" +[[ -d "$REPO_DIR" ]] && command -v wolframscript >/dev/null 2>&1 diff --git a/@ether/library/Language/Categorica/install.sh b/@ether/library/Language/Categorica/install.sh new file mode 100755 index 00000000..a117d3c0 --- /dev/null +++ b/@ether/library/Language/Categorica/install.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/JonathanGorard/Categorica" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/JonathanGorard/Categorica.git "$REPO_DIR" +fi +echo "Categorica cloned to $REPO_DIR. Requires Wolfram Language/Mathematica to use." diff --git a/@ether/library/Language/Categorica/repl.sh b/@ether/library/Language/Categorica/repl.sh new file mode 100755 index 00000000..25f2f1ff --- /dev/null +++ b/@ether/library/Language/Categorica/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec wolframscript diff --git a/@ether/library/Language/Categorica/run.sh b/@ether/library/Language/Categorica/run.sh new file mode 100755 index 00000000..4dfcb675 --- /dev/null +++ b/@ether/library/Language/Categorica/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec wolframscript -file "$1" diff --git a/@ether/library/Language/Cayenne/check.sh b/@ether/library/Language/Cayenne/check.sh new file mode 100755 index 00000000..bcb23dc9 --- /dev/null +++ b/@ether/library/Language/Cayenne/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Cayenne has no modern implementation available." >&2 +exit 1 diff --git a/@ether/library/Language/Cayenne/install.sh b/@ether/library/Language/Cayenne/install.sh new file mode 100755 index 00000000..ba6ff0fb --- /dev/null +++ b/@ether/library/Language/Cayenne/install.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +# Cayenne is a historical dependently-typed language by Lennart Augustsson. +# No actively maintained implementation exists. The original required an old GHC. +echo "Cayenne is a historical language with no modern maintained implementation." >&2 +echo "See: https://en.wikipedia.org/wiki/Cayenne_(programming_language)" >&2 +exit 1 diff --git a/@ether/library/Language/Cayenne/repl.sh b/@ether/library/Language/Cayenne/repl.sh new file mode 100755 index 00000000..bcb23dc9 --- /dev/null +++ b/@ether/library/Language/Cayenne/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Cayenne has no modern implementation available." >&2 +exit 1 diff --git a/@ether/library/Language/Cayenne/run.sh b/@ether/library/Language/Cayenne/run.sh new file mode 100755 index 00000000..bcb23dc9 --- /dev/null +++ b/@ether/library/Language/Cayenne/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Cayenne has no modern implementation available." >&2 +exit 1 diff --git a/@ether/library/Language/Cecil/check.sh b/@ether/library/Language/Cecil/check.sh new file mode 100755 index 00000000..6c918cb2 --- /dev/null +++ b/@ether/library/Language/Cecil/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Cecil has no modern implementation available." >&2 +exit 1 diff --git a/@ether/library/Language/Cecil/install.sh b/@ether/library/Language/Cecil/install.sh new file mode 100755 index 00000000..43c0608c --- /dev/null +++ b/@ether/library/Language/Cecil/install.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +# Cecil is a historical OO language from the University of Washington. +# No actively maintained implementation exists. +echo "Cecil is a historical language. No modern maintained implementation is available." >&2 +echo "See: https://en.wikipedia.org/wiki/Cecil_(programming_language)" >&2 +exit 1 diff --git a/@ether/library/Language/Cecil/repl.sh b/@ether/library/Language/Cecil/repl.sh new file mode 100755 index 00000000..6c918cb2 --- /dev/null +++ b/@ether/library/Language/Cecil/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Cecil has no modern implementation available." >&2 +exit 1 diff --git a/@ether/library/Language/Cecil/run.sh b/@ether/library/Language/Cecil/run.sh new file mode 100755 index 00000000..6c918cb2 --- /dev/null +++ b/@ether/library/Language/Cecil/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Cecil has no modern implementation available." >&2 +exit 1 diff --git a/@ether/library/Language/Cedille/check.sh b/@ether/library/Language/Cedille/check.sh new file mode 100755 index 00000000..4f50fd7f --- /dev/null +++ b/@ether/library/Language/Cedille/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v cedille >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/cedille/cedille" + [[ -d "$REPO_DIR" ]] +} diff --git a/@ether/library/Language/Cedille/install.sh b/@ether/library/Language/Cedille/install.sh new file mode 100755 index 00000000..4eaab57d --- /dev/null +++ b/@ether/library/Language/Cedille/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/cedille/cedille" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/cedille/cedille.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v stack >/dev/null 2>&1; then + stack build +elif command -v cabal >/dev/null 2>&1; then + cabal update && cabal build +else + echo "Install Haskell Stack or cabal first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Cedille/repl.sh b/@ether/library/Language/Cedille/repl.sh new file mode 100755 index 00000000..94019846 --- /dev/null +++ b/@ether/library/Language/Cedille/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Cedille is typically used via its Emacs mode, not a standalone REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Cedille/run.sh b/@ether/library/Language/Cedille/run.sh new file mode 100755 index 00000000..f2694ab6 --- /dev/null +++ b/@ether/library/Language/Cedille/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v cedille >/dev/null 2>&1; then + exec cedille "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/cedille/cedille" + cd "$REPO_DIR" + stack exec cedille -- "$1" +fi diff --git a/@ether/library/Language/CertoraProver/check.sh b/@ether/library/Language/CertoraProver/check.sh new file mode 100755 index 00000000..519a87ba --- /dev/null +++ b/@ether/library/Language/CertoraProver/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v certoraRun >/dev/null 2>&1 diff --git a/@ether/library/Language/CertoraProver/install.sh b/@ether/library/Language/CertoraProver/install.sh new file mode 100755 index 00000000..5d07885e --- /dev/null +++ b/@ether/library/Language/CertoraProver/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +pip install certora-cli || pip3 install certora-cli diff --git a/@ether/library/Language/CertoraProver/repl.sh b/@ether/library/Language/CertoraProver/repl.sh new file mode 100755 index 00000000..c00850ee --- /dev/null +++ b/@ether/library/Language/CertoraProver/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Certora Prover does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/CertoraProver/run.sh b/@ether/library/Language/CertoraProver/run.sh new file mode 100755 index 00000000..648c75f8 --- /dev/null +++ b/@ether/library/Language/CertoraProver/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec certoraRun "$1" diff --git a/@ether/library/Language/Chapel/check.sh b/@ether/library/Language/Chapel/check.sh new file mode 100755 index 00000000..ecb32042 --- /dev/null +++ b/@ether/library/Language/Chapel/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v chpl >/dev/null 2>&1 diff --git a/@ether/library/Language/Chapel/install.sh b/@ether/library/Language/Chapel/install.sh new file mode 100755 index 00000000..eb4d71b6 --- /dev/null +++ b/@ether/library/Language/Chapel/install.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install chapel +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y chapel || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/chapel-lang/chapel" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/chapel-lang/chapel.git "$REPO_DIR" + fi + cd "$REPO_DIR" + source util/quickstart/setchplenv.bash + make -j"$(nproc)" + } +elif command -v dnf >/dev/null 2>&1; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/chapel-lang/chapel" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/chapel-lang/chapel.git "$REPO_DIR" + fi + cd "$REPO_DIR" + source util/quickstart/setchplenv.bash + make -j"$(nproc)" +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm chapel || { + echo "Chapel not in repos. Build from source." >&2; exit 1 + } +else + echo "Unsupported platform." >&2; exit 1 +fi diff --git a/@ether/library/Language/Chapel/repl.sh b/@ether/library/Language/Chapel/repl.sh new file mode 100755 index 00000000..4ae73ff6 --- /dev/null +++ b/@ether/library/Language/Chapel/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Chapel does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Chapel/run.sh b/@ether/library/Language/Chapel/run.sh new file mode 100755 index 00000000..6269569f --- /dev/null +++ b/@ether/library/Language/Chapel/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +chpl "$1" -o /tmp/chapel_out && /tmp/chapel_out diff --git a/@ether/library/Language/Chef/check.sh b/@ether/library/Language/Chef/check.sh new file mode 100755 index 00000000..6572c767 --- /dev/null +++ b/@ether/library/Language/Chef/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/joostrijneveld/Chef" +[[ -d "$REPO_DIR" ]] && command -v python3 >/dev/null 2>&1 diff --git a/@ether/library/Language/Chef/install.sh b/@ether/library/Language/Chef/install.sh new file mode 100755 index 00000000..b2058865 --- /dev/null +++ b/@ether/library/Language/Chef/install.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +# Chef is an esoteric language. Install via a Python interpreter. +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/joostrijneveld/Chef" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/joostrijneveld/Chef.git "$REPO_DIR" +fi diff --git a/@ether/library/Language/Chef/repl.sh b/@ether/library/Language/Chef/repl.sh new file mode 100755 index 00000000..01b96b64 --- /dev/null +++ b/@ether/library/Language/Chef/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Chef does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Chef/run.sh b/@ether/library/Language/Chef/run.sh new file mode 100755 index 00000000..71338f78 --- /dev/null +++ b/@ether/library/Language/Chef/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/joostrijneveld/Chef" +exec python3 "$REPO_DIR/chef.py" "$1" diff --git a/@ether/library/Language/Chicken/check.sh b/@ether/library/Language/Chicken/check.sh new file mode 100755 index 00000000..a89f4131 --- /dev/null +++ b/@ether/library/Language/Chicken/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/igorto/chicken-js" +[[ -d "$REPO_DIR" ]] && ( command -v node >/dev/null 2>&1 || command -v python3 >/dev/null 2>&1 ) diff --git a/@ether/library/Language/Chicken/install.sh b/@ether/library/Language/Chicken/install.sh new file mode 100755 index 00000000..8b531d0a --- /dev/null +++ b/@ether/library/Language/Chicken/install.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -euo pipefail +# Chicken is an esoteric language. Use a JavaScript interpreter. +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/igorto/chicken-js" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/igorto/chicken-js.git "$REPO_DIR" || { + # Fallback: create a simple Python interpreter + mkdir -p "$REPO_DIR" + cat > "$REPO_DIR/chicken.py" << 'PYEOF' +#!/usr/bin/env python3 +"""Simple Chicken language interpreter.""" +import sys +if len(sys.argv) < 2: + print("Usage: chicken.py ", file=sys.stderr) + sys.exit(1) +with open(sys.argv[1]) as f: + code = f.read() +lines = code.strip().split('\n') +program = [line.count('chicken') for line in lines] +stack = [] +for op in program: + if op == 0: sys.exit(0) + elif op == 1: stack.append('chicken') + elif op == 2: + a = stack.pop() + b = stack.pop() + stack.append(a + b) + elif op == 3: + a = stack.pop() + stack.append(chr(a) if isinstance(a, int) else a) + sys.stdout.write(stack[-1]) + else: + stack.append(op) +PYEOF + } +fi diff --git a/@ether/library/Language/Chicken/repl.sh b/@ether/library/Language/Chicken/repl.sh new file mode 100755 index 00000000..8cca3784 --- /dev/null +++ b/@ether/library/Language/Chicken/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Chicken does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Chicken/run.sh b/@ether/library/Language/Chicken/run.sh new file mode 100755 index 00000000..cb3337de --- /dev/null +++ b/@ether/library/Language/Chicken/run.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/igorto/chicken-js" +if [[ -f "$REPO_DIR/chicken.js" ]] && command -v node >/dev/null 2>&1; then + exec node "$REPO_DIR/chicken.js" "$1" +elif [[ -f "$REPO_DIR/chicken.py" ]]; then + exec python3 "$REPO_DIR/chicken.py" "$1" +else + echo "Chicken interpreter not found." >&2; exit 1 +fi diff --git a/@ether/library/Language/Chisel/check.sh b/@ether/library/Language/Chisel/check.sh new file mode 100755 index 00000000..322c3cc5 --- /dev/null +++ b/@ether/library/Language/Chisel/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v sbt >/dev/null 2>&1 diff --git a/@ether/library/Language/Chisel/install.sh b/@ether/library/Language/Chisel/install.sh new file mode 100755 index 00000000..a6fca7fa --- /dev/null +++ b/@ether/library/Language/Chisel/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +# Chisel is a Scala library. Install sbt and use it as a dependency. +if [[ "$(uname)" == "Darwin" ]]; then + brew install sbt +elif command -v apt-get >/dev/null 2>&1; then + echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | sudo tee /etc/apt/sources.list.d/sbt.list + curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add - + sudo apt-get update && sudo apt-get install -y sbt +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y sbt || { + echo "Install sbt manually from https://www.scala-sbt.org/" >&2; exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm sbt +else + echo "Install sbt manually from https://www.scala-sbt.org/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Chisel/repl.sh b/@ether/library/Language/Chisel/repl.sh new file mode 100755 index 00000000..4a794aed --- /dev/null +++ b/@ether/library/Language/Chisel/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sbt console diff --git a/@ether/library/Language/Chisel/run.sh b/@ether/library/Language/Chisel/run.sh new file mode 100755 index 00000000..651ff904 --- /dev/null +++ b/@ether/library/Language/Chisel/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sbt "runMain $(basename "$1" .scala)" diff --git a/@ether/library/Language/ChucK/check.sh b/@ether/library/Language/ChucK/check.sh new file mode 100755 index 00000000..d5d275f6 --- /dev/null +++ b/@ether/library/Language/ChucK/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v chuck >/dev/null 2>&1 diff --git a/@ether/library/Language/ChucK/install.sh b/@ether/library/Language/ChucK/install.sh new file mode 100755 index 00000000..a4503cf7 --- /dev/null +++ b/@ether/library/Language/ChucK/install.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install chuck +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y chuck +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y chuck || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ccrma/chuck" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ccrma/chuck.git "$REPO_DIR" + fi + cd "$REPO_DIR/src" + make linux-alsa + sudo cp chuck /usr/local/bin/ + } +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm chuck +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ccrma/chuck" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ccrma/chuck.git "$REPO_DIR" + fi + cd "$REPO_DIR/src" + make linux-alsa + sudo cp chuck /usr/local/bin/ +fi diff --git a/@ether/library/Language/ChucK/repl.sh b/@ether/library/Language/ChucK/repl.sh new file mode 100755 index 00000000..831f6fac --- /dev/null +++ b/@ether/library/Language/ChucK/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec chuck --shell diff --git a/@ether/library/Language/ChucK/run.sh b/@ether/library/Language/ChucK/run.sh new file mode 100755 index 00000000..a69b9db4 --- /dev/null +++ b/@ether/library/Language/ChucK/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec chuck "$1" diff --git a/@ether/library/Language/Church/check.sh b/@ether/library/Language/Church/check.sh new file mode 100755 index 00000000..7ba11770 --- /dev/null +++ b/@ether/library/Language/Church/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/probmods/webchurch" +[[ -d "$REPO_DIR/node_modules" ]] && command -v node >/dev/null 2>&1 diff --git a/@ether/library/Language/Church/install.sh b/@ether/library/Language/Church/install.sh new file mode 100755 index 00000000..f1351f77 --- /dev/null +++ b/@ether/library/Language/Church/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/probmods/webchurch" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/probmods/webchurch.git "$REPO_DIR" +fi +cd "$REPO_DIR" +npm install diff --git a/@ether/library/Language/Church/repl.sh b/@ether/library/Language/Church/repl.sh new file mode 100755 index 00000000..ff001317 --- /dev/null +++ b/@ether/library/Language/Church/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Church does not provide a CLI REPL. Use the web interface at probmods.org." >&2 +exit 1 diff --git a/@ether/library/Language/Church/run.sh b/@ether/library/Language/Church/run.sh new file mode 100755 index 00000000..2fde9dbf --- /dev/null +++ b/@ether/library/Language/Church/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/probmods/webchurch" +cd "$REPO_DIR" +exec node webchurch.js "$1" diff --git a/@ether/library/Language/Chyp/check.sh b/@ether/library/Language/Chyp/check.sh new file mode 100755 index 00000000..861d1637 --- /dev/null +++ b/@ether/library/Language/Chyp/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v chyp >/dev/null 2>&1 || python3 -c "import chyp" 2>/dev/null diff --git a/@ether/library/Language/Chyp/install.sh b/@ether/library/Language/Chyp/install.sh new file mode 100755 index 00000000..5dbaaaf1 --- /dev/null +++ b/@ether/library/Language/Chyp/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +pip install chyp || pip3 install chyp || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/akissinger/chyp" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/akissinger/chyp.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install -e . || pip3 install -e . +} diff --git a/@ether/library/Language/Chyp/repl.sh b/@ether/library/Language/Chyp/repl.sh new file mode 100755 index 00000000..2675c7bf --- /dev/null +++ b/@ether/library/Language/Chyp/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec chyp diff --git a/@ether/library/Language/Chyp/run.sh b/@ether/library/Language/Chyp/run.sh new file mode 100755 index 00000000..809052c8 --- /dev/null +++ b/@ether/library/Language/Chyp/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v chyp >/dev/null 2>&1; then + exec chyp "$1" +else + exec python3 -m chyp "$1" +fi diff --git a/@ether/library/Language/Cirq/check.sh b/@ether/library/Language/Cirq/check.sh new file mode 100755 index 00000000..c99e0165 --- /dev/null +++ b/@ether/library/Language/Cirq/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import cirq" 2>/dev/null diff --git a/@ether/library/Language/Cirq/install.sh b/@ether/library/Language/Cirq/install.sh new file mode 100755 index 00000000..8c9c0642 --- /dev/null +++ b/@ether/library/Language/Cirq/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +pip install cirq || pip3 install cirq diff --git a/@ether/library/Language/Cirq/repl.sh b/@ether/library/Language/Cirq/repl.sh new file mode 100755 index 00000000..da98e5a4 --- /dev/null +++ b/@ether/library/Language/Cirq/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import cirq; help(cirq)" 2>/dev/null || python3 diff --git a/@ether/library/Language/Cirq/run.sh b/@ether/library/Language/Cirq/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/Cirq/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Civet/check.sh b/@ether/library/Language/Civet/check.sh new file mode 100755 index 00000000..d7fdde36 --- /dev/null +++ b/@ether/library/Language/Civet/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v civet >/dev/null 2>&1 diff --git a/@ether/library/Language/Civet/install.sh b/@ether/library/Language/Civet/install.sh new file mode 100755 index 00000000..455cf7df --- /dev/null +++ b/@ether/library/Language/Civet/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +npm install -g @danielx/civet diff --git a/@ether/library/Language/Civet/repl.sh b/@ether/library/Language/Civet/repl.sh new file mode 100755 index 00000000..ee08e4e7 --- /dev/null +++ b/@ether/library/Language/Civet/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec civet diff --git a/@ether/library/Language/Civet/run.sh b/@ether/library/Language/Civet/run.sh new file mode 100755 index 00000000..b068019e --- /dev/null +++ b/@ether/library/Language/Civet/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec civet "$1" diff --git a/@ether/library/Language/Clarity/check.sh b/@ether/library/Language/Clarity/check.sh new file mode 100755 index 00000000..bfe4a83f --- /dev/null +++ b/@ether/library/Language/Clarity/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v clarinet >/dev/null 2>&1 || command -v clarity-cli >/dev/null 2>&1 diff --git a/@ether/library/Language/Clarity/install.sh b/@ether/library/Language/Clarity/install.sh new file mode 100755 index 00000000..b9b3c9e8 --- /dev/null +++ b/@ether/library/Language/Clarity/install.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +# Clarity: Stacks blockchain smart contract language - https://clarity-lang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hirosystems/clarinet" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/hirosystems/clarinet.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install clarinet +elif command -v cargo >/dev/null 2>&1; then + cargo install clarinet +else + echo "Install Rust/Cargo first, then run: cargo install clarinet" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Clarity/packages.sh b/@ether/library/Language/Clarity/packages.sh new file mode 100755 index 00000000..15e87fbb --- /dev/null +++ b/@ether/library/Language/Clarity/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Clarity does not have a standard package manager." +echo "Clarinet templates: https://github.com/hirosystems/clarinet" diff --git a/@ether/library/Language/Clarity/repl.sh b/@ether/library/Language/Clarity/repl.sh new file mode 100755 index 00000000..dd7f6752 --- /dev/null +++ b/@ether/library/Language/Clarity/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec clarinet console diff --git a/@ether/library/Language/Clarity/run.sh b/@ether/library/Language/Clarity/run.sh new file mode 100755 index 00000000..e46dd33d --- /dev/null +++ b/@ether/library/Language/Clarity/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec clarinet check "$@" diff --git a/@ether/library/Language/Clojure/check.sh b/@ether/library/Language/Clojure/check.sh new file mode 100755 index 00000000..bc057913 --- /dev/null +++ b/@ether/library/Language/Clojure/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v clj >/dev/null 2>&1 || command -v clojure >/dev/null 2>&1 diff --git a/@ether/library/Language/Clojure/install.sh b/@ether/library/Language/Clojure/install.sh new file mode 100755 index 00000000..287c22d3 --- /dev/null +++ b/@ether/library/Language/Clojure/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official install: https://clojure.org/guides/install_clojure +if [[ "$(uname)" == "Darwin" ]]; then + brew install clojure/tools/clojure +else + # Official method for all Linux: linux-install.sh + # Requires: bash, curl, rlwrap, java + curl -L -O https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh + chmod +x linux-install.sh && sudo ./linux-install.sh && rm linux-install.sh +fi diff --git a/@ether/library/Language/Clojure/packages.sh b/@ether/library/Language/Clojure/packages.sh new file mode 100755 index 00000000..2180f5c0 --- /dev/null +++ b/@ether/library/Language/Clojure/packages.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Clojure" +REGISTRIES=( + "Clojars: https://clojars.org" + "Maven Central: https://search.maven.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v lein &>/dev/null; then + lein search "$@" + else + echo "Visit: https://clojars.org/search?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://clojars.org/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to deps.edn:" + echo " :deps {$1/$ {:mvn/version \"VERSION\"}}" + echo "" + echo "Or add to project.clj:" + echo " [$1 \"VERSION\"]" + echo "" + echo "Find the version at: https://clojars.org/$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Clojure/repl.sh b/@ether/library/Language/Clojure/repl.sh new file mode 100755 index 00000000..42fe269d --- /dev/null +++ b/@ether/library/Language/Clojure/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec clj diff --git a/@ether/library/Language/Clojure/run.sh b/@ether/library/Language/Clojure/run.sh new file mode 100755 index 00000000..664f3b7d --- /dev/null +++ b/@ether/library/Language/Clojure/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec clojure "$@" diff --git a/@ether/library/Language/Coconut/check.sh b/@ether/library/Language/Coconut/check.sh new file mode 100755 index 00000000..087b50f2 --- /dev/null +++ b/@ether/library/Language/Coconut/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v coconut >/dev/null 2>&1 diff --git a/@ether/library/Language/Coconut/install.sh b/@ether/library/Language/Coconut/install.sh new file mode 100755 index 00000000..b1cbabd6 --- /dev/null +++ b/@ether/library/Language/Coconut/install.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +# Coconut - Python superset for functional programming +if command -v pip3 >/dev/null 2>&1; then + pip3 install coconut +elif command -v pip >/dev/null 2>&1; then + pip install coconut +else + echo "pip/pip3 not found. Install Python first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Coconut/packages.sh b/@ether/library/Language/Coconut/packages.sh new file mode 100755 index 00000000..7810e274 --- /dev/null +++ b/@ether/library/Language/Coconut/packages.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://pypi.org" + +usage() { + echo "Coconut Package Manager (pip / Python ecosystem)" + echo "" + echo "Coconut uses the Python/pip ecosystem for package management." + echo "" + echo "Registry: $REGISTRY" + echo "" + echo "Usage: packages.sh [args]" + echo "" + echo "Commands:" + echo " search Search for packages" + echo " info Show package information" + echo " install Install a package" +} + +cmd_search() { + local query="$1" + if command -v pip &>/dev/null; then + pip index versions "$query" 2>/dev/null || echo "Visit: $REGISTRY/search/?q=$query" + else + echo "pip not found. Search online:" + echo " $REGISTRY/search/?q=$query" + fi +} + +cmd_info() { + local pkg="$1" + if command -v pip &>/dev/null; then + pip show "$pkg" 2>/dev/null || echo "Visit: $REGISTRY/project/$pkg/" + else + echo "pip not found. View online:" + echo " $REGISTRY/project/$pkg/" + fi +} + +cmd_install() { + local pkg="$1" + if command -v pip &>/dev/null; then + pip install "$pkg" + else + echo "pip not found. Install Python first." + exit 1 + fi +} + +case "${1:-}" in + search) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh search "; exit 1; } + cmd_search "$1" + ;; + info) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh info "; exit 1; } + cmd_info "$1" + ;; + install) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh install "; exit 1; } + cmd_install "$1" + ;; + *) + usage + ;; +esac diff --git a/@ether/library/Language/Coconut/repl.sh b/@ether/library/Language/Coconut/repl.sh new file mode 100755 index 00000000..cf18dfe7 --- /dev/null +++ b/@ether/library/Language/Coconut/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec coconut diff --git a/@ether/library/Language/Coconut/run.sh b/@ether/library/Language/Coconut/run.sh new file mode 100755 index 00000000..6610b3d3 --- /dev/null +++ b/@ether/library/Language/Coconut/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec coconut "$@" diff --git a/@ether/library/Language/CoffeeScript/check.sh b/@ether/library/Language/CoffeeScript/check.sh new file mode 100755 index 00000000..28020626 --- /dev/null +++ b/@ether/library/Language/CoffeeScript/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v coffee >/dev/null 2>&1 diff --git a/@ether/library/Language/CoffeeScript/install.sh b/@ether/library/Language/CoffeeScript/install.sh new file mode 100755 index 00000000..63f2fd9e --- /dev/null +++ b/@ether/library/Language/CoffeeScript/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +npm install -g coffeescript diff --git a/@ether/library/Language/CoffeeScript/repl.sh b/@ether/library/Language/CoffeeScript/repl.sh new file mode 100755 index 00000000..611f0a9f --- /dev/null +++ b/@ether/library/Language/CoffeeScript/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec coffee diff --git a/@ether/library/Language/CoffeeScript/run.sh b/@ether/library/Language/CoffeeScript/run.sh new file mode 100755 index 00000000..33f172b3 --- /dev/null +++ b/@ether/library/Language/CoffeeScript/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec coffee "$1" diff --git a/@ether/library/Language/Cognate/check.sh b/@ether/library/Language/Cognate/check.sh new file mode 100755 index 00000000..329ba0df --- /dev/null +++ b/@ether/library/Language/Cognate/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v cognate >/dev/null 2>&1 diff --git a/@ether/library/Language/Cognate/install.sh b/@ether/library/Language/Cognate/install.sh new file mode 100755 index 00000000..8cc1e300 --- /dev/null +++ b/@ether/library/Language/Cognate/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/cognate-lang/cognate" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/cognate-lang/cognate.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" +sudo make install || cp cognate "$HOME/.local/bin/" diff --git a/@ether/library/Language/Cognate/repl.sh b/@ether/library/Language/Cognate/repl.sh new file mode 100755 index 00000000..24b2a6fb --- /dev/null +++ b/@ether/library/Language/Cognate/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Cognate does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Cognate/run.sh b/@ether/library/Language/Cognate/run.sh new file mode 100755 index 00000000..e7ce4c68 --- /dev/null +++ b/@ether/library/Language/Cognate/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cognate "$1" diff --git a/@ether/library/Language/CommonLisp/check.sh b/@ether/library/Language/CommonLisp/check.sh new file mode 100755 index 00000000..4991d8c6 --- /dev/null +++ b/@ether/library/Language/CommonLisp/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v sbcl >/dev/null 2>&1 diff --git a/@ether/library/Language/CommonLisp/install.sh b/@ether/library/Language/CommonLisp/install.sh new file mode 100755 index 00000000..0b975898 --- /dev/null +++ b/@ether/library/Language/CommonLisp/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install sbcl +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y sbcl +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y sbcl +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm sbcl +else + echo "Unsupported package manager. Install SBCL manually." >&2; exit 1 +fi diff --git a/@ether/library/Language/CommonLisp/repl.sh b/@ether/library/Language/CommonLisp/repl.sh new file mode 100755 index 00000000..32ba00ed --- /dev/null +++ b/@ether/library/Language/CommonLisp/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sbcl diff --git a/@ether/library/Language/CommonLisp/run.sh b/@ether/library/Language/CommonLisp/run.sh new file mode 100755 index 00000000..4daaee59 --- /dev/null +++ b/@ether/library/Language/CommonLisp/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sbcl --script "$1" diff --git a/@ether/library/Language/ComponentPascal/check.sh b/@ether/library/Language/ComponentPascal/check.sh new file mode 100755 index 00000000..d53ae64d --- /dev/null +++ b/@ether/library/Language/ComponentPascal/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v fpc >/dev/null 2>&1 diff --git a/@ether/library/Language/ComponentPascal/install.sh b/@ether/library/Language/ComponentPascal/install.sh new file mode 100755 index 00000000..55d5595b --- /dev/null +++ b/@ether/library/Language/ComponentPascal/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Component Pascal is implemented by BlackBox Component Builder. +# Free Pascal can compile some Component Pascal constructs. +if [[ "$(uname)" == "Darwin" ]]; then + brew install fpc +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y fp-compiler +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y fpc +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm fpc +else + echo "Unsupported package manager. Install Free Pascal manually." >&2; exit 1 +fi diff --git a/@ether/library/Language/ComponentPascal/repl.sh b/@ether/library/Language/ComponentPascal/repl.sh new file mode 100755 index 00000000..9310d538 --- /dev/null +++ b/@ether/library/Language/ComponentPascal/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Component Pascal does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ComponentPascal/run.sh b/@ether/library/Language/ComponentPascal/run.sh new file mode 100755 index 00000000..5e72f339 --- /dev/null +++ b/@ether/library/Language/ComponentPascal/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +OUT="/tmp/cp_out_$$" +fpc -o"$OUT" "$1" && "$OUT" +rm -f "$OUT" diff --git a/@ether/library/Language/ConcurrentPascal/check.sh b/@ether/library/Language/ConcurrentPascal/check.sh new file mode 100755 index 00000000..d53ae64d --- /dev/null +++ b/@ether/library/Language/ConcurrentPascal/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v fpc >/dev/null 2>&1 diff --git a/@ether/library/Language/ConcurrentPascal/install.sh b/@ether/library/Language/ConcurrentPascal/install.sh new file mode 100755 index 00000000..1486fc37 --- /dev/null +++ b/@ether/library/Language/ConcurrentPascal/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Concurrent Pascal by Per Brinch Hansen is a historical language. +# Free Pascal is the closest modern alternative. +if [[ "$(uname)" == "Darwin" ]]; then + brew install fpc +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y fp-compiler +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y fpc +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm fpc +else + echo "Unsupported package manager. Install Free Pascal manually." >&2; exit 1 +fi diff --git a/@ether/library/Language/ConcurrentPascal/repl.sh b/@ether/library/Language/ConcurrentPascal/repl.sh new file mode 100755 index 00000000..98a18e4d --- /dev/null +++ b/@ether/library/Language/ConcurrentPascal/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Concurrent Pascal does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ConcurrentPascal/run.sh b/@ether/library/Language/ConcurrentPascal/run.sh new file mode 100755 index 00000000..fdc45cbf --- /dev/null +++ b/@ether/library/Language/ConcurrentPascal/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +OUT="/tmp/conpas_out_$$" +fpc -o"$OUT" "$1" && "$OUT" +rm -f "$OUT" diff --git a/@ether/library/Language/CreuSAT/check.sh b/@ether/library/Language/CreuSAT/check.sh new file mode 100755 index 00000000..5f9653fb --- /dev/null +++ b/@ether/library/Language/CreuSAT/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/sarsko/CreuSAT" +[[ -f "$REPO_DIR/target/release/CreuSAT" ]] || [[ -f "$REPO_DIR/target/release/creusat" ]] diff --git a/@ether/library/Language/CreuSAT/install.sh b/@ether/library/Language/CreuSAT/install.sh new file mode 100755 index 00000000..8f50407b --- /dev/null +++ b/@ether/library/Language/CreuSAT/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/sarsko/CreuSAT" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/sarsko/CreuSAT.git "$REPO_DIR" +fi +cd "$REPO_DIR" +cargo build --release diff --git a/@ether/library/Language/CreuSAT/repl.sh b/@ether/library/Language/CreuSAT/repl.sh new file mode 100755 index 00000000..3b04788c --- /dev/null +++ b/@ether/library/Language/CreuSAT/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CreuSAT is a SAT solver and does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/CreuSAT/run.sh b/@ether/library/Language/CreuSAT/run.sh new file mode 100755 index 00000000..f505d2c9 --- /dev/null +++ b/@ether/library/Language/CreuSAT/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/sarsko/CreuSAT" +if [[ -f "$REPO_DIR/target/release/CreuSAT" ]]; then + exec "$REPO_DIR/target/release/CreuSAT" "$1" +else + exec "$REPO_DIR/target/release/creusat" "$1" +fi diff --git a/@ether/library/Language/Creusot/check.sh b/@ether/library/Language/Creusot/check.sh new file mode 100755 index 00000000..cf6aa8ac --- /dev/null +++ b/@ether/library/Language/Creusot/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v cargo-creusot >/dev/null 2>&1 || command -v creusot-rustc >/dev/null 2>&1 diff --git a/@ether/library/Language/Creusot/install.sh b/@ether/library/Language/Creusot/install.sh new file mode 100755 index 00000000..029bbe3b --- /dev/null +++ b/@ether/library/Language/Creusot/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/creusot-rs/creusot" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/creusot-rs/creusot.git "$REPO_DIR" +fi +cd "$REPO_DIR" +cargo install --path creusot diff --git a/@ether/library/Language/Creusot/repl.sh b/@ether/library/Language/Creusot/repl.sh new file mode 100755 index 00000000..8908d387 --- /dev/null +++ b/@ether/library/Language/Creusot/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Creusot is a verification tool and does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Creusot/run.sh b/@ether/library/Language/Creusot/run.sh new file mode 100755 index 00000000..95bf71d2 --- /dev/null +++ b/@ether/library/Language/Creusot/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cargo creusot "$@" diff --git a/@ether/library/Language/Crystal/check.sh b/@ether/library/Language/Crystal/check.sh new file mode 100755 index 00000000..4d0f00b1 --- /dev/null +++ b/@ether/library/Language/Crystal/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v crystal >/dev/null 2>&1 diff --git a/@ether/library/Language/Crystal/install.sh b/@ether/library/Language/Crystal/install.sh new file mode 100755 index 00000000..2afa35f5 --- /dev/null +++ b/@ether/library/Language/Crystal/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install crystal +elif command -v apt-get >/dev/null 2>&1; then + curl -fsSL https://crystal-lang.org/install.sh | sudo bash +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y crystal +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm crystal shards +else + echo "Unsupported platform. See https://crystal-lang.org/install/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Crystal/packages.sh b/@ether/library/Language/Crystal/packages.sh new file mode 100755 index 00000000..c55f18d4 --- /dev/null +++ b/@ether/library/Language/Crystal/packages.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Crystal" +REGISTRIES=( + "Shardbox: https://shardbox.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://shardbox.org/search?query=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v shards &>/dev/null; then + shards info "$1" 2>/dev/null || echo "Visit: https://shardbox.org/search?query=$1" + else + echo "Visit: https://shardbox.org/search?query=$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to shard.yml dependencies:" + echo " dependencies:" + echo " $1:" + echo " github: OWNER/$1" + echo "" + echo "Then run: shards install" + echo "Find the repo at: https://shardbox.org/search?query=$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Crystal/repl.sh b/@ether/library/Language/Crystal/repl.sh new file mode 100755 index 00000000..081b1f39 --- /dev/null +++ b/@ether/library/Language/Crystal/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v icr >/dev/null 2>&1; then + exec icr +else + echo "Crystal does not include a built-in REPL. Install icr: https://github.com/crystal-community/icr" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Crystal/run.sh b/@ether/library/Language/Crystal/run.sh new file mode 100755 index 00000000..53ec1f9c --- /dev/null +++ b/@ether/library/Language/Crystal/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec crystal run "$1" diff --git a/@ether/library/Language/CuPPL/check.sh b/@ether/library/Language/CuPPL/check.sh new file mode 100755 index 00000000..1daac179 --- /dev/null +++ b/@ether/library/Language/CuPPL/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CuPPL has no public implementation available." >&2 +exit 1 diff --git a/@ether/library/Language/CuPPL/install.sh b/@ether/library/Language/CuPPL/install.sh new file mode 100755 index 00000000..9cadc8a3 --- /dev/null +++ b/@ether/library/Language/CuPPL/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# CuPPL is a research probabilistic programming language for CUDA. +# See: https://arxiv.org/abs/2010.08454 +# No publicly maintained implementation is available. +echo "CuPPL is a research language described in a paper. No public implementation available." >&2 +echo "See: https://arxiv.org/abs/2010.08454" >&2 +exit 1 diff --git a/@ether/library/Language/CuPPL/repl.sh b/@ether/library/Language/CuPPL/repl.sh new file mode 100755 index 00000000..1daac179 --- /dev/null +++ b/@ether/library/Language/CuPPL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CuPPL has no public implementation available." >&2 +exit 1 diff --git a/@ether/library/Language/CuPPL/run.sh b/@ether/library/Language/CuPPL/run.sh new file mode 100755 index 00000000..1daac179 --- /dev/null +++ b/@ether/library/Language/CuPPL/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "CuPPL has no public implementation available." >&2 +exit 1 diff --git a/@ether/library/Language/Cycle.js/check.sh b/@ether/library/Language/Cycle.js/check.sh new file mode 100755 index 00000000..b6f5b7a5 --- /dev/null +++ b/@ether/library/Language/Cycle.js/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v node >/dev/null 2>&1 && node -e "require('@cycle/run')" 2>/dev/null diff --git a/@ether/library/Language/Cycle.js/install.sh b/@ether/library/Language/Cycle.js/install.sh new file mode 100755 index 00000000..b3948278 --- /dev/null +++ b/@ether/library/Language/Cycle.js/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +npm install @cycle/run @cycle/dom xstream diff --git a/@ether/library/Language/Cycle.js/repl.sh b/@ether/library/Language/Cycle.js/repl.sh new file mode 100755 index 00000000..21d1f479 --- /dev/null +++ b/@ether/library/Language/Cycle.js/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec node -e "const {run} = require('@cycle/run'); console.log('Cycle.js loaded.'); require('repl').start('cycle> ')" diff --git a/@ether/library/Language/Cycle.js/run.sh b/@ether/library/Language/Cycle.js/run.sh new file mode 100755 index 00000000..f082fff1 --- /dev/null +++ b/@ether/library/Language/Cycle.js/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec node "$1" diff --git a/@ether/library/Language/Cypher/check.sh b/@ether/library/Language/Cypher/check.sh new file mode 100755 index 00000000..3a28db95 --- /dev/null +++ b/@ether/library/Language/Cypher/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v cypher-shell >/dev/null 2>&1 || command -v neo4j >/dev/null 2>&1 diff --git a/@ether/library/Language/Cypher/install.sh b/@ether/library/Language/Cypher/install.sh new file mode 100755 index 00000000..be5b4fb3 --- /dev/null +++ b/@ether/library/Language/Cypher/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Cypher is Neo4j's query language. Install Neo4j or cypher-shell. +if [[ "$(uname)" == "Darwin" ]]; then + brew install neo4j +elif command -v apt-get >/dev/null 2>&1; then + # Add Neo4j repository + curl -fsSL https://debian.neo4j.com/neotechnology.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/neo4j.gpg + echo "deb [signed-by=/usr/share/keyrings/neo4j.gpg] https://debian.neo4j.com stable latest" | sudo tee /etc/apt/sources.list.d/neo4j.list + sudo apt-get update && sudo apt-get install -y neo4j +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y neo4j || { + echo "Install Neo4j manually from https://neo4j.com/download/" >&2; exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm neo4j || { + echo "Install Neo4j from AUR." >&2; exit 1 + } +else + echo "Unsupported platform. Install Neo4j manually." >&2; exit 1 +fi diff --git a/@ether/library/Language/Cypher/repl.sh b/@ether/library/Language/Cypher/repl.sh new file mode 100755 index 00000000..29d68063 --- /dev/null +++ b/@ether/library/Language/Cypher/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cypher-shell diff --git a/@ether/library/Language/Cypher/run.sh b/@ether/library/Language/Cypher/run.sh new file mode 100755 index 00000000..c1aae4bb --- /dev/null +++ b/@ether/library/Language/Cypher/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cypher-shell < "$1" diff --git a/@ether/library/Language/D/check.sh b/@ether/library/Language/D/check.sh new file mode 100755 index 00000000..6ba61698 --- /dev/null +++ b/@ether/library/Language/D/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v dmd >/dev/null 2>&1 || command -v ldc2 >/dev/null 2>&1 diff --git a/@ether/library/Language/D/install.sh b/@ether/library/Language/D/install.sh new file mode 100755 index 00000000..e43df13b --- /dev/null +++ b/@ether/library/Language/D/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install dmd +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y dmd || { + # Use official installer + curl -fsS https://dlang.org/install.sh | bash -s dmd + } +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y dmd || { + curl -fsS https://dlang.org/install.sh | bash -s dmd + } +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm dmd +else + curl -fsS https://dlang.org/install.sh | bash -s dmd +fi diff --git a/@ether/library/Language/D/packages.sh b/@ether/library/Language/D/packages.sh new file mode 100755 index 00000000..9832e84b --- /dev/null +++ b/@ether/library/Language/D/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="D" +REGISTRIES=( + "DUB Registry: https://code.dlang.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v dub &>/dev/null; then + dub search "$@" + else + echo "Visit: https://code.dlang.org/?search=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://code.dlang.org/packages/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + if command -v dub &>/dev/null; then + dub fetch "$1" + else + echo "Install dub first, then run: dub fetch $1" + fi + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/D/repl.sh b/@ether/library/Language/D/repl.sh new file mode 100755 index 00000000..38bf75b5 --- /dev/null +++ b/@ether/library/Language/D/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "D does not provide a built-in REPL. Use rdmd for script-like execution." >&2 +exit 1 diff --git a/@ether/library/Language/D/run.sh b/@ether/library/Language/D/run.sh new file mode 100755 index 00000000..510e8b7b --- /dev/null +++ b/@ether/library/Language/D/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec rdmd "$1" diff --git a/@ether/library/Language/DIMACS/check.sh b/@ether/library/Language/DIMACS/check.sh new file mode 100755 index 00000000..a97f38b8 --- /dev/null +++ b/@ether/library/Language/DIMACS/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# DIMACS is a data format; always available +exit 0 diff --git a/@ether/library/Language/DIMACS/install.sh b/@ether/library/Language/DIMACS/install.sh new file mode 100755 index 00000000..f0d8a7cc --- /dev/null +++ b/@ether/library/Language/DIMACS/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# DIMACS is a data format for SAT/graph problems. No installation needed. +echo "DIMACS is a data format. No installation required." diff --git a/@ether/library/Language/DIMACS/repl.sh b/@ether/library/Language/DIMACS/repl.sh new file mode 100755 index 00000000..ab7aa9c0 --- /dev/null +++ b/@ether/library/Language/DIMACS/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "DIMACS is a data format. No REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/DIMACS/run.sh b/@ether/library/Language/DIMACS/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/DIMACS/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/Dafny/check.sh b/@ether/library/Language/Dafny/check.sh new file mode 100755 index 00000000..be7d33e0 --- /dev/null +++ b/@ether/library/Language/Dafny/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v dafny >/dev/null 2>&1 diff --git a/@ether/library/Language/Dafny/install.sh b/@ether/library/Language/Dafny/install.sh new file mode 100755 index 00000000..388548b3 --- /dev/null +++ b/@ether/library/Language/Dafny/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install dafny +elif command -v dotnet >/dev/null 2>&1; then + dotnet tool install --global dafny +else + # Download binary release + OS="$(uname -s | tr '[:upper:]' '[:lower:]')" + ARCH="$(uname -m)" + case "$ARCH" in + x86_64) ARCH="x64" ;; + aarch64|arm64) ARCH="arm64" ;; + esac + VERSION=$(curl -fsSL https://api.github.com/repos/dafny-lang/dafny/releases/latest | grep tag_name | cut -d'"' -f4 | sed 's/^v//') + curl -fsSL "https://github.com/dafny-lang/dafny/releases/download/v${VERSION}/dafny-${VERSION}-${ARCH}-ubuntu-20.04.zip" -o /tmp/dafny.zip + sudo unzip -o /tmp/dafny.zip -d /opt/dafny + sudo ln -sf /opt/dafny/dafny/dafny /usr/local/bin/dafny + rm -f /tmp/dafny.zip +fi diff --git a/@ether/library/Language/Dafny/repl.sh b/@ether/library/Language/Dafny/repl.sh new file mode 100755 index 00000000..47fca97a --- /dev/null +++ b/@ether/library/Language/Dafny/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Dafny does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Dafny/run.sh b/@ether/library/Language/Dafny/run.sh new file mode 100755 index 00000000..8b6c1ab2 --- /dev/null +++ b/@ether/library/Language/Dafny/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec dafny run "$1" diff --git a/@ether/library/Language/Dart/check.sh b/@ether/library/Language/Dart/check.sh new file mode 100755 index 00000000..9d6a01cd --- /dev/null +++ b/@ether/library/Language/Dart/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v dart >/dev/null 2>&1 diff --git a/@ether/library/Language/Dart/install.sh b/@ether/library/Language/Dart/install.sh new file mode 100755 index 00000000..716971dd --- /dev/null +++ b/@ether/library/Language/Dart/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official install: https://dart.dev/get-dart +if [[ "$(uname)" == "Darwin" ]]; then + brew tap dart-lang/dart && brew install dart +elif command -v apt-get >/dev/null 2>&1; then + if [[ ! -f /usr/share/keyrings/dart.gpg ]]; then + sudo apt-get update && sudo apt-get install -y apt-transport-https + wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo gpg --yes --dearmor -o /usr/share/keyrings/dart.gpg + echo "deb [signed-by=/usr/share/keyrings/dart.gpg arch=$(dpkg --print-architecture)] https://storage.googleapis.com/download.dartlang.org/linux/debian stable main" | sudo tee /etc/apt/sources.list.d/dart_stable.list > /dev/null + sudo apt-get update + fi + sudo apt-get install -y dart +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm dart +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Dart/packages.sh b/@ether/library/Language/Dart/packages.sh new file mode 100755 index 00000000..45403499 --- /dev/null +++ b/@ether/library/Language/Dart/packages.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Dart" +REGISTRIES=( + "pub.dev: https://pub.dev" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://pub.dev/packages?q=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://pub.dev/packages/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + dart pub add "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Dart/repl.sh b/@ether/library/Language/Dart/repl.sh new file mode 100755 index 00000000..c1fccde1 --- /dev/null +++ b/@ether/library/Language/Dart/repl.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Dart does not have a CLI REPL." +echo "Use DartPad for interactive Dart: https://dartpad.dev/" +exit 1 diff --git a/@ether/library/Language/Dart/run.sh b/@ether/library/Language/Dart/run.sh new file mode 100755 index 00000000..2d3c351c --- /dev/null +++ b/@ether/library/Language/Dart/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec dart run "$@" diff --git a/@ether/library/Language/Datalog/check.sh b/@ether/library/Language/Datalog/check.sh new file mode 100755 index 00000000..893eaefe --- /dev/null +++ b/@ether/library/Language/Datalog/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v souffle >/dev/null 2>&1 diff --git a/@ether/library/Language/Datalog/install.sh b/@ether/library/Language/Datalog/install.sh new file mode 100755 index 00000000..35319e32 --- /dev/null +++ b/@ether/library/Language/Datalog/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Souffle Datalog engine - https://souffle-lang.github.io/install +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Souffle from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/souffle-lang/souffle" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/souffle-lang/souffle.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cmake -S . -B build && cmake --build build -j"$(nproc)" && sudo cmake --install build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install souffle-lang/souffle/souffle +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y souffle +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y souffle +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm souffle +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/Datalog/repl.sh b/@ether/library/Language/Datalog/repl.sh new file mode 100755 index 00000000..4d903b03 --- /dev/null +++ b/@ether/library/Language/Datalog/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Datalog (Souffle) has no interactive REPL. Use: souffle " >&2 +exit 1 diff --git a/@ether/library/Language/Datalog/run.sh b/@ether/library/Language/Datalog/run.sh new file mode 100755 index 00000000..e6bf8b37 --- /dev/null +++ b/@ether/library/Language/Datalog/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec souffle "$1" diff --git a/@ether/library/Language/Dedukti/check.sh b/@ether/library/Language/Dedukti/check.sh new file mode 100755 index 00000000..a6781520 --- /dev/null +++ b/@ether/library/Language/Dedukti/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v dk >/dev/null 2>&1 || command -v dkcheck >/dev/null 2>&1 diff --git a/@ether/library/Language/Dedukti/install.sh b/@ether/library/Language/Dedukti/install.sh new file mode 100755 index 00000000..2ef77654 --- /dev/null +++ b/@ether/library/Language/Dedukti/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Dedukti - https://github.com/Deducteam/Dedukti +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Deducteam/Dedukti" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Deducteam/Dedukti.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make && make install + exit 0 +fi +# Install via opam (recommended) +if command -v opam >/dev/null 2>&1; then + eval "$(opam env)" || true + opam install -y dedukti +else + echo "opam is required. Install OCaml/opam first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Dedukti/repl.sh b/@ether/library/Language/Dedukti/repl.sh new file mode 100755 index 00000000..6688b659 --- /dev/null +++ b/@ether/library/Language/Dedukti/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Dedukti has no interactive REPL. Use: dk check " >&2 +exit 1 diff --git a/@ether/library/Language/Dedukti/run.sh b/@ether/library/Language/Dedukti/run.sh new file mode 100755 index 00000000..3c5c38fa --- /dev/null +++ b/@ether/library/Language/Dedukti/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v dk >/dev/null 2>&1; then + exec dk check "$1" +else + exec dkcheck "$1" +fi diff --git a/@ether/library/Language/DependentML/check.sh b/@ether/library/Language/DependentML/check.sh new file mode 100755 index 00000000..c63702c5 --- /dev/null +++ b/@ether/library/Language/DependentML/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v patscc >/dev/null 2>&1 || command -v atscc >/dev/null 2>&1 diff --git a/@ether/library/Language/DependentML/install.sh b/@ether/library/Language/DependentML/install.sh new file mode 100755 index 00000000..b5ca34f7 --- /dev/null +++ b/@ether/library/Language/DependentML/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# DependentML is a historical research language (predecessor of ATS). +# The closest modern implementation is ATS (Applied Type System). +# Install ATS2 as the successor: https://www.ats-lang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/githwxi/ATS-Postiats" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/githwxi/ATS-Postiats.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./configure && make && sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install ats2-postiats +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y ats2-lang +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm ats2 +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/DependentML/repl.sh b/@ether/library/Language/DependentML/repl.sh new file mode 100755 index 00000000..f6fab96e --- /dev/null +++ b/@ether/library/Language/DependentML/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "DependentML (ATS) has no interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/DependentML/run.sh b/@ether/library/Language/DependentML/run.sh new file mode 100755 index 00000000..43b859b0 --- /dev/null +++ b/@ether/library/Language/DependentML/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# DependentML successor: ATS2 +patscc -o /tmp/dml_out "$1" && /tmp/dml_out diff --git a/@ether/library/Language/Dhall/check.sh b/@ether/library/Language/Dhall/check.sh new file mode 100755 index 00000000..145123ae --- /dev/null +++ b/@ether/library/Language/Dhall/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v dhall >/dev/null 2>&1 diff --git a/@ether/library/Language/Dhall/install.sh b/@ether/library/Language/Dhall/install.sh new file mode 100755 index 00000000..60b25016 --- /dev/null +++ b/@ether/library/Language/Dhall/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Dhall - https://dhall-lang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/dhall-lang/dhall-haskell" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/dhall-lang/dhall-haskell.git "$REPO_DIR" + fi + cd "$REPO_DIR" && stack install dhall + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install dhall +elif command -v cabal >/dev/null 2>&1; then + cabal update && cabal install dhall +elif command -v stack >/dev/null 2>&1; then + stack install dhall +else + echo "Install Haskell Stack or cabal first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Dhall/repl.sh b/@ether/library/Language/Dhall/repl.sh new file mode 100755 index 00000000..60ed3f6b --- /dev/null +++ b/@ether/library/Language/Dhall/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec dhall repl diff --git a/@ether/library/Language/Dhall/run.sh b/@ether/library/Language/Dhall/run.sh new file mode 100755 index 00000000..883de92f --- /dev/null +++ b/@ether/library/Language/Dhall/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec dhall <<< "$(cat "$1")" diff --git a/@ether/library/Language/Dice/check.sh b/@ether/library/Language/Dice/check.sh new file mode 100755 index 00000000..caf5072e --- /dev/null +++ b/@ether/library/Language/Dice/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/SHoltzen/dice" +[[ -x "$REPO_DIR/dice" ]] || command -v dice >/dev/null 2>&1 diff --git a/@ether/library/Language/Dice/install.sh b/@ether/library/Language/Dice/install.sh new file mode 100755 index 00000000..08677d72 --- /dev/null +++ b/@ether/library/Language/Dice/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Dice - https://github.com/SHoltzen/dice +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/SHoltzen/dice" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/SHoltzen/dice.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v opam >/dev/null 2>&1; then + eval "$(opam env)" || true + opam install -y . --deps-only || true +fi +make diff --git a/@ether/library/Language/Dice/repl.sh b/@ether/library/Language/Dice/repl.sh new file mode 100755 index 00000000..9536af73 --- /dev/null +++ b/@ether/library/Language/Dice/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Dice has no interactive REPL. Use: dice " >&2 +exit 1 diff --git a/@ether/library/Language/Dice/run.sh b/@ether/library/Language/Dice/run.sh new file mode 100755 index 00000000..93e6f473 --- /dev/null +++ b/@ether/library/Language/Dice/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/SHoltzen/dice" +if [[ -x "$REPO_DIR/dice" ]]; then + exec "$REPO_DIR/dice" "$1" +else + exec dice "$1" +fi diff --git a/@ether/library/Language/DisCoPy/check.sh b/@ether/library/Language/DisCoPy/check.sh new file mode 100755 index 00000000..2c6de50c --- /dev/null +++ b/@ether/library/Language/DisCoPy/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import discopy" 2>/dev/null diff --git a/@ether/library/Language/DisCoPy/install.sh b/@ether/library/Language/DisCoPy/install.sh new file mode 100755 index 00000000..597764ac --- /dev/null +++ b/@ether/library/Language/DisCoPy/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install DisCoPy - https://discopy.org/ https://github.com/discopy/discopy +pip install discopy diff --git a/@ether/library/Language/DisCoPy/repl.sh b/@ether/library/Language/DisCoPy/repl.sh new file mode 100755 index 00000000..05e0460d --- /dev/null +++ b/@ether/library/Language/DisCoPy/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 -c "import discopy; print('DisCoPy loaded'); import code; code.interact(local={'discopy': discopy})" diff --git a/@ether/library/Language/DisCoPy/run.sh b/@ether/library/Language/DisCoPy/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/DisCoPy/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/DocBook/check.sh b/@ether/library/Language/DocBook/check.sh new file mode 100755 index 00000000..78dde8f1 --- /dev/null +++ b/@ether/library/Language/DocBook/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# DocBook is a markup format; always available +exit 0 diff --git a/@ether/library/Language/DocBook/install.sh b/@ether/library/Language/DocBook/install.sh new file mode 100755 index 00000000..05b2aa86 --- /dev/null +++ b/@ether/library/Language/DocBook/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# DocBook is an XML markup format. No installation needed. +# Optionally install xmllint for validation. +echo "DocBook is a markup format. No installation required." diff --git a/@ether/library/Language/DocBook/repl.sh b/@ether/library/Language/DocBook/repl.sh new file mode 100755 index 00000000..0672c442 --- /dev/null +++ b/@ether/library/Language/DocBook/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "DocBook is a markup format. No REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/DocBook/run.sh b/@ether/library/Language/DocBook/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/DocBook/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/Docker/check.sh b/@ether/library/Language/Docker/check.sh new file mode 100755 index 00000000..0707cb0d --- /dev/null +++ b/@ether/library/Language/Docker/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v docker >/dev/null 2>&1 diff --git a/@ether/library/Language/Docker/install.sh b/@ether/library/Language/Docker/install.sh new file mode 100755 index 00000000..82b3fa6d --- /dev/null +++ b/@ether/library/Language/Docker/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official install: https://docs.docker.com/engine/install/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask docker +elif command -v apt-get >/dev/null 2>&1; then + # Docker's official apt repository (not docker.io from Ubuntu repos) + sudo apt-get update + sudo apt-get install -y ca-certificates curl + sudo install -m 0755 -d /etc/apt/keyrings + sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc + sudo chmod a+r /etc/apt/keyrings/docker.asc + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + sudo apt-get update + sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + sudo usermod -aG docker "$USER" +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y dnf-plugins-core + sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo + sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + sudo systemctl enable --now docker + sudo usermod -aG docker "$USER" +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm docker docker-compose + sudo systemctl enable --now docker + sudo usermod -aG docker "$USER" +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Docker/repl.sh b/@ether/library/Language/Docker/repl.sh new file mode 100755 index 00000000..67454267 --- /dev/null +++ b/@ether/library/Language/Docker/repl.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v docker >/dev/null 2>&1; then + echo "Docker interactive shell:" + echo " docker run -it ubuntu bash" + echo " docker run -it alpine sh" + echo " docker run -it python python3" + echo "" + echo "Or specify an image: docker run -it " + exec docker run -it ubuntu bash +else + echo "Docker is not installed." + exit 1 +fi diff --git a/@ether/library/Language/Docker/run.sh b/@ether/library/Language/Docker/run.sh new file mode 100755 index 00000000..e00b3498 --- /dev/null +++ b/@ether/library/Language/Docker/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +target="$1" +if [[ -f "$target" ]]; then + docker build -f "$target" . +elif [[ -d "$target" ]]; then + cd "$target" && docker compose up 2>/dev/null || docker-compose up +fi diff --git a/@ether/library/Language/Doxygen/check.sh b/@ether/library/Language/Doxygen/check.sh new file mode 100755 index 00000000..2e99db9f --- /dev/null +++ b/@ether/library/Language/Doxygen/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v doxygen >/dev/null 2>&1 diff --git a/@ether/library/Language/Doxygen/install.sh b/@ether/library/Language/Doxygen/install.sh new file mode 100755 index 00000000..ba44e99a --- /dev/null +++ b/@ether/library/Language/Doxygen/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Doxygen - https://www.doxygen.nl/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/doxygen/doxygen" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/doxygen/doxygen.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cmake -S . -B build -G "Unix Makefiles" && cmake --build build -j"$(nproc)" && sudo cmake --install build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install doxygen +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y doxygen +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y doxygen +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm doxygen +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/Doxygen/repl.sh b/@ether/library/Language/Doxygen/repl.sh new file mode 100755 index 00000000..74325449 --- /dev/null +++ b/@ether/library/Language/Doxygen/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Doxygen has no interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Doxygen/run.sh b/@ether/library/Language/Doxygen/run.sh new file mode 100755 index 00000000..e465cea0 --- /dev/null +++ b/@ether/library/Language/Doxygen/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec doxygen "$1" diff --git a/@ether/library/Language/DreamBerd/check.sh b/@ether/library/Language/DreamBerd/check.sh new file mode 100755 index 00000000..7fbddf36 --- /dev/null +++ b/@ether/library/Language/DreamBerd/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/TodePond/DreamBerd" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/DreamBerd/install.sh b/@ether/library/Language/DreamBerd/install.sh new file mode 100755 index 00000000..5ba33a6c --- /dev/null +++ b/@ether/library/Language/DreamBerd/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install DreamBerd - https://github.com/TodePond/DreamBerd +# DreamBerd is a satirical/esoteric language specification. +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/TodePond/DreamBerd" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/TodePond/DreamBerd.git "$REPO_DIR" +fi +echo "DreamBerd repo cloned to $REPO_DIR. This is a specification, not a runnable implementation." diff --git a/@ether/library/Language/DreamBerd/repl.sh b/@ether/library/Language/DreamBerd/repl.sh new file mode 100755 index 00000000..91eaa0af --- /dev/null +++ b/@ether/library/Language/DreamBerd/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "DreamBerd has no REPL (it is a satirical language specification)." >&2 +exit 1 diff --git a/@ether/library/Language/DreamBerd/run.sh b/@ether/library/Language/DreamBerd/run.sh new file mode 100755 index 00000000..b92811ed --- /dev/null +++ b/@ether/library/Language/DreamBerd/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "DreamBerd is a specification/joke language. Displaying file:" +cat "$1" diff --git a/@ether/library/Language/Dyna/check.sh b/@ether/library/Language/Dyna/check.sh new file mode 100755 index 00000000..67ca8f37 --- /dev/null +++ b/@ether/library/Language/Dyna/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/nwf/dyna" +[[ -d "$REPO_DIR" ]] || command -v dyna >/dev/null 2>&1 diff --git a/@ether/library/Language/Dyna/install.sh b/@ether/library/Language/Dyna/install.sh new file mode 100755 index 00000000..a4ec0455 --- /dev/null +++ b/@ether/library/Language/Dyna/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Dyna - a weighted logic programming language +# https://github.com/nwf/dyna +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/nwf/dyna" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/nwf/dyna.git "$REPO_DIR" +fi +cd "$REPO_DIR" +pip install -e . 2>/dev/null || { + echo "Dyna requires Python. Install dependencies manually from $REPO_DIR" >&2 +} diff --git a/@ether/library/Language/Dyna/repl.sh b/@ether/library/Language/Dyna/repl.sh new file mode 100755 index 00000000..833664a5 --- /dev/null +++ b/@ether/library/Language/Dyna/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Dyna has no interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Dyna/run.sh b/@ether/library/Language/Dyna/run.sh new file mode 100755 index 00000000..b78cd27a --- /dev/null +++ b/@ether/library/Language/Dyna/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v dyna >/dev/null 2>&1; then + exec dyna "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/nwf/dyna" + exec python3 "$REPO_DIR/dyna/main.py" "$1" +fi diff --git a/@ether/library/Language/Dyon/check.sh b/@ether/library/Language/Dyon/check.sh new file mode 100755 index 00000000..535f1e9e --- /dev/null +++ b/@ether/library/Language/Dyon/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v dyon_interactive >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/PistonDevelopers/dyon" + [[ -x "$REPO_DIR/target/release/dyon_interactive" ]] +} diff --git a/@ether/library/Language/Dyon/install.sh b/@ether/library/Language/Dyon/install.sh new file mode 100755 index 00000000..85969017 --- /dev/null +++ b/@ether/library/Language/Dyon/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Dyon - https://github.com/PistonDevelopers/dyon +if command -v cargo >/dev/null 2>&1; then + cargo install dyon_interactive +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/PistonDevelopers/dyon" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/PistonDevelopers/dyon.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release +fi diff --git a/@ether/library/Language/Dyon/repl.sh b/@ether/library/Language/Dyon/repl.sh new file mode 100755 index 00000000..98aeab08 --- /dev/null +++ b/@ether/library/Language/Dyon/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Dyon has no interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Dyon/run.sh b/@ether/library/Language/Dyon/run.sh new file mode 100755 index 00000000..a6368b26 --- /dev/null +++ b/@ether/library/Language/Dyon/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v dyon_interactive >/dev/null 2>&1; then + exec dyon_interactive "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/PistonDevelopers/dyon" + exec "$REPO_DIR/target/release/dyon_interactive" "$1" +fi diff --git a/@ether/library/Language/ENV/check.sh b/@ether/library/Language/ENV/check.sh new file mode 100755 index 00000000..dd48738a --- /dev/null +++ b/@ether/library/Language/ENV/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# ENV is a configuration format; always available +exit 0 diff --git a/@ether/library/Language/ENV/install.sh b/@ether/library/Language/ENV/install.sh new file mode 100755 index 00000000..e8ad990d --- /dev/null +++ b/@ether/library/Language/ENV/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# ENV (.env) is a configuration format for environment variables. No installation needed. +echo "ENV is a configuration format. No installation required." diff --git a/@ether/library/Language/ENV/repl.sh b/@ether/library/Language/ENV/repl.sh new file mode 100755 index 00000000..0d8f2a24 --- /dev/null +++ b/@ether/library/Language/ENV/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "ENV is a configuration format. No REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/ENV/run.sh b/@ether/library/Language/ENV/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/ENV/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/ETheoremProver/check.sh b/@ether/library/Language/ETheoremProver/check.sh new file mode 100755 index 00000000..a38ff722 --- /dev/null +++ b/@ether/library/Language/ETheoremProver/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v eprover >/dev/null 2>&1 diff --git a/@ether/library/Language/ETheoremProver/install.sh b/@ether/library/Language/ETheoremProver/install.sh new file mode 100755 index 00000000..497859d9 --- /dev/null +++ b/@ether/library/Language/ETheoremProver/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install E Theorem Prover - https://github.com/eprover/eprover +# https://wwwlehre.dhbw-stuttgart.de/~sschulz/E/E.html +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/eprover/eprover" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/eprover/eprover.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./configure && make -j"$(nproc)" && sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install eprover +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y eprover +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm eprover +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/ETheoremProver/repl.sh b/@ether/library/Language/ETheoremProver/repl.sh new file mode 100755 index 00000000..e527b40d --- /dev/null +++ b/@ether/library/Language/ETheoremProver/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "E Theorem Prover has no interactive REPL. Use: eprover --auto " >&2 +exit 1 diff --git a/@ether/library/Language/ETheoremProver/run.sh b/@ether/library/Language/ETheoremProver/run.sh new file mode 100755 index 00000000..434e0b7f --- /dev/null +++ b/@ether/library/Language/ETheoremProver/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec eprover --auto "$1" diff --git a/@ether/library/Language/Edison/check.sh b/@ether/library/Language/Edison/check.sh new file mode 100755 index 00000000..1e4daf9a --- /dev/null +++ b/@ether/library/Language/Edison/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Edison has no modern implementation +exit 1 diff --git a/@ether/library/Language/Edison/install.sh b/@ether/library/Language/Edison/install.sh new file mode 100755 index 00000000..dd773970 --- /dev/null +++ b/@ether/library/Language/Edison/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +# Edison is a historical programming language (1981, Brinch Hansen). +# No modern implementation is widely available. +echo "Edison is a historical language with no modern implementation available." +echo "See: https://en.wikipedia.org/wiki/Edison_(programming_language)" diff --git a/@ether/library/Language/Edison/repl.sh b/@ether/library/Language/Edison/repl.sh new file mode 100755 index 00000000..ecef89f3 --- /dev/null +++ b/@ether/library/Language/Edison/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Edison has no modern implementation or REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Edison/run.sh b/@ether/library/Language/Edison/run.sh new file mode 100755 index 00000000..2bed8c19 --- /dev/null +++ b/@ether/library/Language/Edison/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Edison has no modern implementation. Displaying file:" +cat "$1" diff --git a/@ether/library/Language/EditorConfig/check.sh b/@ether/library/Language/EditorConfig/check.sh new file mode 100755 index 00000000..5cb4372a --- /dev/null +++ b/@ether/library/Language/EditorConfig/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# EditorConfig is a configuration format; always available +exit 0 diff --git a/@ether/library/Language/EditorConfig/install.sh b/@ether/library/Language/EditorConfig/install.sh new file mode 100755 index 00000000..4103cd46 --- /dev/null +++ b/@ether/library/Language/EditorConfig/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# EditorConfig is a configuration format. No installation needed. +# Optionally install editorconfig-checker for validation. +echo "EditorConfig is a configuration format. No installation required." diff --git a/@ether/library/Language/EditorConfig/repl.sh b/@ether/library/Language/EditorConfig/repl.sh new file mode 100755 index 00000000..b8667a99 --- /dev/null +++ b/@ether/library/Language/EditorConfig/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "EditorConfig is a configuration format. No REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/EditorConfig/run.sh b/@ether/library/Language/EditorConfig/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/EditorConfig/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/Edward/check.sh b/@ether/library/Language/Edward/check.sh new file mode 100755 index 00000000..fe12fb7b --- /dev/null +++ b/@ether/library/Language/Edward/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import edward" 2>/dev/null diff --git a/@ether/library/Language/Edward/install.sh b/@ether/library/Language/Edward/install.sh new file mode 100755 index 00000000..dc53bb19 --- /dev/null +++ b/@ether/library/Language/Edward/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Edward - https://github.com/blei-lab/edward +# Edward2 is now part of TensorFlow Probability +pip install edward diff --git a/@ether/library/Language/Edward/repl.sh b/@ether/library/Language/Edward/repl.sh new file mode 100755 index 00000000..5900494c --- /dev/null +++ b/@ether/library/Language/Edward/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 -c "import edward; print('Edward loaded'); import code; code.interact(local={'edward': edward})" diff --git a/@ether/library/Language/Edward/run.sh b/@ether/library/Language/Edward/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/Edward/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Eff/check.sh b/@ether/library/Language/Eff/check.sh new file mode 100755 index 00000000..c4a4706d --- /dev/null +++ b/@ether/library/Language/Eff/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v eff >/dev/null 2>&1 diff --git a/@ether/library/Language/Eff/install.sh b/@ether/library/Language/Eff/install.sh new file mode 100755 index 00000000..80d3c5f8 --- /dev/null +++ b/@ether/library/Language/Eff/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Eff - https://www.eff-lang.org/ https://github.com/matijapretnar/eff +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/matijapretnar/eff" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/matijapretnar/eff.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make + exit 0 +fi +# Install via opam +if command -v opam >/dev/null 2>&1; then + eval "$(opam env)" || true + opam install -y eff +else + echo "opam is required. Install OCaml/opam first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Eff/repl.sh b/@ether/library/Language/Eff/repl.sh new file mode 100755 index 00000000..46c592b7 --- /dev/null +++ b/@ether/library/Language/Eff/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec eff diff --git a/@ether/library/Language/Eff/run.sh b/@ether/library/Language/Eff/run.sh new file mode 100755 index 00000000..caae5d4a --- /dev/null +++ b/@ether/library/Language/Eff/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec eff "$1" diff --git a/@ether/library/Language/Effekt/check.sh b/@ether/library/Language/Effekt/check.sh new file mode 100755 index 00000000..7bd775e0 --- /dev/null +++ b/@ether/library/Language/Effekt/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v effekt >/dev/null 2>&1 diff --git a/@ether/library/Language/Effekt/install.sh b/@ether/library/Language/Effekt/install.sh new file mode 100755 index 00000000..dfaf2a04 --- /dev/null +++ b/@ether/library/Language/Effekt/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Effekt - https://effekt-lang.org/ https://github.com/effekt-lang/effekt +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/effekt-lang/effekt" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/effekt-lang/effekt.git "$REPO_DIR" + fi + cd "$REPO_DIR" && sbt assemble + exit 0 +fi +# Install via npm (official method) +npm install -g @aspect-build/effekt 2>/dev/null || npm install -g effekt 2>/dev/null || { + echo "Trying sbt build..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/effekt-lang/effekt" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/effekt-lang/effekt.git "$REPO_DIR" + fi + cd "$REPO_DIR" && sbt assemble +} diff --git a/@ether/library/Language/Effekt/repl.sh b/@ether/library/Language/Effekt/repl.sh new file mode 100755 index 00000000..563c6482 --- /dev/null +++ b/@ether/library/Language/Effekt/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec effekt diff --git a/@ether/library/Language/Effekt/run.sh b/@ether/library/Language/Effekt/run.sh new file mode 100755 index 00000000..974610bb --- /dev/null +++ b/@ether/library/Language/Effekt/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec effekt "$1" diff --git a/@ether/library/Language/Eiffel/check.sh b/@ether/library/Language/Eiffel/check.sh new file mode 100755 index 00000000..dc021389 --- /dev/null +++ b/@ether/library/Language/Eiffel/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v ec >/dev/null 2>&1 diff --git a/@ether/library/Language/Eiffel/install.sh b/@ether/library/Language/Eiffel/install.sh new file mode 100755 index 00000000..bb25d6cf --- /dev/null +++ b/@ether/library/Language/Eiffel/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Eiffel - EiffelStudio +if [[ "$(uname)" == "Darwin" ]]; then + echo "EiffelStudio is not in Homebrew. Download from https://www.eiffel.org/downloads" >&2 + echo "Or install via: brew install --cask eiffelstudio (if available)" >&2 + exit 1 +elif command -v apt-get >/dev/null 2>&1; then + # EiffelStudio may be available via PPA or manual download + echo "Download EiffelStudio from https://www.eiffel.org/downloads" >&2 + echo "For Debian/Ubuntu, check: https://www.eiffel.org/doc/solutions/EiffelStudio_on_Linux" >&2 + exit 1 +elif command -v dnf >/dev/null 2>&1; then + echo "Download EiffelStudio from https://www.eiffel.org/downloads" >&2; exit 1 +elif command -v pacman >/dev/null 2>&1; then + echo "Check AUR for eiffelstudio: yay -S eiffelstudio" >&2; exit 1 +else + echo "Download EiffelStudio from https://www.eiffel.org/downloads" >&2; exit 1 +fi diff --git a/@ether/library/Language/Eiffel/packages.sh b/@ether/library/Language/Eiffel/packages.sh new file mode 100755 index 00000000..0d2e2599 --- /dev/null +++ b/@ether/library/Language/Eiffel/packages.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Eiffel uses the IRON package repository (largely historical)." +echo " https://iron.eiffel.com" +echo "" +echo "Most Eiffel libraries are distributed via GitHub." diff --git a/@ether/library/Language/Eiffel/repl.sh b/@ether/library/Language/Eiffel/repl.sh new file mode 100755 index 00000000..81f6dd43 --- /dev/null +++ b/@ether/library/Language/Eiffel/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Eiffel does not have an interactive REPL. Use EiffelStudio IDE or compile with: ec " diff --git a/@ether/library/Language/Eiffel/run.sh b/@ether/library/Language/Eiffel/run.sh new file mode 100755 index 00000000..44e88d92 --- /dev/null +++ b/@ether/library/Language/Eiffel/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ec "$@" diff --git a/@ether/library/Language/Elixir/check.sh b/@ether/library/Language/Elixir/check.sh new file mode 100755 index 00000000..323e03f6 --- /dev/null +++ b/@ether/library/Language/Elixir/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v elixir >/dev/null 2>&1 diff --git a/@ether/library/Language/Elixir/install.sh b/@ether/library/Language/Elixir/install.sh new file mode 100755 index 00000000..51e6b3a0 --- /dev/null +++ b/@ether/library/Language/Elixir/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official install: https://elixir-lang.org/install.html +if [[ "$(uname)" == "Darwin" ]]; then + brew install elixir +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm elixir +elif command -v apt-get >/dev/null 2>&1; then + # Default apt packages are severely outdated; use Erlang Solutions repo + if [[ ! -f /etc/apt/sources.list.d/erlang-solutions.list ]]; then + wget -q https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb -O /tmp/erlang-solutions.deb + sudo dpkg -i /tmp/erlang-solutions.deb + rm -f /tmp/erlang-solutions.deb + sudo apt-get update + fi + sudo apt-get install -y elixir +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y elixir +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Elixir/packages.sh b/@ether/library/Language/Elixir/packages.sh new file mode 100755 index 00000000..cd3f9e2d --- /dev/null +++ b/@ether/library/Language/Elixir/packages.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Elixir" +REGISTRIES=( + "Hex: https://hex.pm" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v mix &>/dev/null; then + mix hex.search "$@" + else + echo "Visit: https://hex.pm/packages?search=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v mix &>/dev/null; then + mix hex.info "$1" + else + echo "Visit: https://hex.pm/packages/$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to mix.exs deps:" + echo " {:$1, \"~> VERSION\"}" + echo "" + echo "Then run: mix deps.get" + echo "Details: https://hex.pm/packages/$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Elixir/repl.sh b/@ether/library/Language/Elixir/repl.sh new file mode 100755 index 00000000..f043992e --- /dev/null +++ b/@ether/library/Language/Elixir/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec iex diff --git a/@ether/library/Language/Elixir/run.sh b/@ether/library/Language/Elixir/run.sh new file mode 100755 index 00000000..d98fa3ba --- /dev/null +++ b/@ether/library/Language/Elixir/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec elixir "$@" diff --git a/@ether/library/Language/Elm/check.sh b/@ether/library/Language/Elm/check.sh new file mode 100755 index 00000000..5cde0a85 --- /dev/null +++ b/@ether/library/Language/Elm/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v elm >/dev/null 2>&1 diff --git a/@ether/library/Language/Elm/install.sh b/@ether/library/Language/Elm/install.sh new file mode 100755 index 00000000..cd569ef2 --- /dev/null +++ b/@ether/library/Language/Elm/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Elm - https://guide.elm-lang.org/install/elm.html +if [[ "$(uname)" == "Darwin" ]]; then + brew install elm +else + # Official binary installer + npm install -g elm 2>/dev/null || { + ARCH=$(uname -m) + if [[ "$ARCH" == "x86_64" ]]; then + curl -fsSL https://github.com/elm/compiler/releases/latest/download/binary-for-linux-64-bit.gz | gzip -d > /tmp/elm + chmod +x /tmp/elm && sudo mv /tmp/elm /usr/local/bin/elm + else + echo "Elm official binaries are x86_64 only on Linux. Use npm: npm install -g elm" >&2; exit 1 + fi + } +fi diff --git a/@ether/library/Language/Elm/packages.sh b/@ether/library/Language/Elm/packages.sh new file mode 100755 index 00000000..d2e09644 --- /dev/null +++ b/@ether/library/Language/Elm/packages.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Elm" +REGISTRIES=( + "Elm Packages: https://package.elm-lang.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://package.elm-lang.org/?q=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://package.elm-lang.org/packages/$1/latest" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + elm install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Elm/repl.sh b/@ether/library/Language/Elm/repl.sh new file mode 100755 index 00000000..3a0c913f --- /dev/null +++ b/@ether/library/Language/Elm/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec elm repl diff --git a/@ether/library/Language/Elm/run.sh b/@ether/library/Language/Elm/run.sh new file mode 100755 index 00000000..7976c45d --- /dev/null +++ b/@ether/library/Language/Elm/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec elm make "$1" diff --git a/@ether/library/Language/Elvish/check.sh b/@ether/library/Language/Elvish/check.sh new file mode 100755 index 00000000..b03b6210 --- /dev/null +++ b/@ether/library/Language/Elvish/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v elvish >/dev/null 2>&1 diff --git a/@ether/library/Language/Elvish/install.sh b/@ether/library/Language/Elvish/install.sh new file mode 100755 index 00000000..9ee05773 --- /dev/null +++ b/@ether/library/Language/Elvish/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Elvish - https://elv.sh/ https://github.com/elves/elvish +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/elves/elvish" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/elves/elvish.git "$REPO_DIR" + fi + cd "$REPO_DIR" && go build -o elvish ./cmd/elvish && sudo mv elvish /usr/local/bin/ + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install elvish +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y elvish +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y elvish +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm elvish +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/Elvish/repl.sh b/@ether/library/Language/Elvish/repl.sh new file mode 100755 index 00000000..d0061a10 --- /dev/null +++ b/@ether/library/Language/Elvish/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec elvish diff --git a/@ether/library/Language/Elvish/run.sh b/@ether/library/Language/Elvish/run.sh new file mode 100755 index 00000000..37d3dcf5 --- /dev/null +++ b/@ether/library/Language/Elvish/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec elvish "$1" diff --git a/@ether/library/Language/Emerald/check.sh b/@ether/library/Language/Emerald/check.sh new file mode 100755 index 00000000..d0ef03a2 --- /dev/null +++ b/@ether/library/Language/Emerald/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Emerald has no modern implementation +exit 1 diff --git a/@ether/library/Language/Emerald/install.sh b/@ether/library/Language/Emerald/install.sh new file mode 100755 index 00000000..17557895 --- /dev/null +++ b/@ether/library/Language/Emerald/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +# Emerald is a historical distributed object-oriented language. +# No widely maintained modern implementation. +# See: https://en.wikipedia.org/wiki/Emerald_(programming_language) +echo "Emerald is a historical language. No modern implementation readily available." diff --git a/@ether/library/Language/Emerald/repl.sh b/@ether/library/Language/Emerald/repl.sh new file mode 100755 index 00000000..c4718fa1 --- /dev/null +++ b/@ether/library/Language/Emerald/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Emerald has no modern implementation or REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Emerald/run.sh b/@ether/library/Language/Emerald/run.sh new file mode 100755 index 00000000..95b5b9d4 --- /dev/null +++ b/@ether/library/Language/Emerald/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Emerald has no modern implementation. Displaying file:" +cat "$1" diff --git a/@ether/library/Language/Enso/check.sh b/@ether/library/Language/Enso/check.sh new file mode 100755 index 00000000..36a8d344 --- /dev/null +++ b/@ether/library/Language/Enso/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v enso >/dev/null 2>&1 || [[ -x /opt/enso/bin/enso ]] diff --git a/@ether/library/Language/Enso/install.sh b/@ether/library/Language/Enso/install.sh new file mode 100755 index 00000000..a48ff1af --- /dev/null +++ b/@ether/library/Language/Enso/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Enso - https://github.com/enso-org/enso +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/enso-org/enso" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/enso-org/enso.git "$REPO_DIR" + fi + cd "$REPO_DIR" && sbt engine-runner/assembly + exit 0 +fi +# Download release binary +OS=$(uname -s | tr '[:upper:]' '[:lower:]') +ARCH=$(uname -m) +case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64) ARCH="aarch64" ;; +esac +VERSION=$(curl -sSL https://api.github.com/repos/enso-org/enso/releases/latest | grep tag_name | cut -d'"' -f4) +curl -fsSL "https://github.com/enso-org/enso/releases/download/${VERSION}/enso-engine-${VERSION#enso-}-${OS}-${ARCH}.tar.gz" -o /tmp/enso.tar.gz +sudo mkdir -p /opt/enso && sudo tar -C /opt/enso --strip-components=1 -xzf /tmp/enso.tar.gz +rm -f /tmp/enso.tar.gz +echo "Enso installed to /opt/enso" diff --git a/@ether/library/Language/Enso/repl.sh b/@ether/library/Language/Enso/repl.sh new file mode 100755 index 00000000..5c2389b1 --- /dev/null +++ b/@ether/library/Language/Enso/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +if command -v enso >/dev/null 2>&1; then + exec enso repl +elif [[ -x /opt/enso/bin/enso ]]; then + exec /opt/enso/bin/enso repl +else + echo "Enso not found." >&2; exit 1 +fi diff --git a/@ether/library/Language/Enso/run.sh b/@ether/library/Language/Enso/run.sh new file mode 100755 index 00000000..dfaa556c --- /dev/null +++ b/@ether/library/Language/Enso/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v enso >/dev/null 2>&1; then + exec enso run "$1" +elif [[ -x /opt/enso/bin/enso ]]; then + exec /opt/enso/bin/enso run "$1" +else + echo "Enso not found." >&2; exit 1 +fi diff --git a/@ether/library/Language/Epigram/check.sh b/@ether/library/Language/Epigram/check.sh new file mode 100755 index 00000000..7cbd07d6 --- /dev/null +++ b/@ether/library/Language/Epigram/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Epigram has no modern implementation +exit 1 diff --git a/@ether/library/Language/Epigram/install.sh b/@ether/library/Language/Epigram/install.sh new file mode 100755 index 00000000..e19848fc --- /dev/null +++ b/@ether/library/Language/Epigram/install.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +# Epigram is a historical dependently typed language by Conor McBride. +# No actively maintained implementation. Successor concepts in Idris/Agda. +# See: http://www.e-pig.org/ +echo "Epigram is a historical language. No modern implementation available." +echo "Consider Idris or Agda as successors." diff --git a/@ether/library/Language/Epigram/repl.sh b/@ether/library/Language/Epigram/repl.sh new file mode 100755 index 00000000..6f99a16f --- /dev/null +++ b/@ether/library/Language/Epigram/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Epigram has no modern implementation or REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Epigram/run.sh b/@ether/library/Language/Epigram/run.sh new file mode 100755 index 00000000..31195f9e --- /dev/null +++ b/@ether/library/Language/Epigram/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Epigram has no modern implementation. Displaying file:" +cat "$1" diff --git a/@ether/library/Language/Erlang/check.sh b/@ether/library/Language/Erlang/check.sh new file mode 100755 index 00000000..16197985 --- /dev/null +++ b/@ether/library/Language/Erlang/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v erl >/dev/null 2>&1 diff --git a/@ether/library/Language/Erlang/install.sh b/@ether/library/Language/Erlang/install.sh new file mode 100755 index 00000000..cce08cf1 --- /dev/null +++ b/@ether/library/Language/Erlang/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install erlang +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y erlang +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y erlang +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm erlang +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Erlang/packages.sh b/@ether/library/Language/Erlang/packages.sh new file mode 100755 index 00000000..b8c875d5 --- /dev/null +++ b/@ether/library/Language/Erlang/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Erlang" +REGISTRIES=( + "Hex: https://hex.pm" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v rebar3 &>/dev/null; then + rebar3 hex search "$@" + else + echo "Visit: https://hex.pm/packages?search=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://hex.pm/packages/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to rebar.config deps:" + echo " {$1, \"VERSION\"}" + echo "" + echo "Then run: rebar3 compile" + echo "Details: https://hex.pm/packages/$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Erlang/repl.sh b/@ether/library/Language/Erlang/repl.sh new file mode 100755 index 00000000..0ff4f733 --- /dev/null +++ b/@ether/library/Language/Erlang/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec erl diff --git a/@ether/library/Language/Erlang/run.sh b/@ether/library/Language/Erlang/run.sh new file mode 100755 index 00000000..4566d3e4 --- /dev/null +++ b/@ether/library/Language/Erlang/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec escript "$@" diff --git a/@ether/library/Language/Euclid/check.sh b/@ether/library/Language/Euclid/check.sh new file mode 100755 index 00000000..c8e263a3 --- /dev/null +++ b/@ether/library/Language/Euclid/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Euclid has no modern implementation +exit 1 diff --git a/@ether/library/Language/Euclid/install.sh b/@ether/library/Language/Euclid/install.sh new file mode 100755 index 00000000..e0ba1cbb --- /dev/null +++ b/@ether/library/Language/Euclid/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +# Euclid is a historical verification language (1977, Lampson et al.). +# No modern implementation is available. +echo "Euclid is a historical language. No modern implementation available." +echo "See: https://en.wikipedia.org/wiki/Euclid_(programming_language)" diff --git a/@ether/library/Language/Euclid/repl.sh b/@ether/library/Language/Euclid/repl.sh new file mode 100755 index 00000000..11a2b66f --- /dev/null +++ b/@ether/library/Language/Euclid/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Euclid has no modern implementation or REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Euclid/run.sh b/@ether/library/Language/Euclid/run.sh new file mode 100755 index 00000000..609ffe8d --- /dev/null +++ b/@ether/library/Language/Euclid/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Euclid has no modern implementation. Displaying file:" +cat "$1" diff --git a/@ether/library/Language/EventB/check.sh b/@ether/library/Language/EventB/check.sh new file mode 100755 index 00000000..1b9986ee --- /dev/null +++ b/@ether/library/Language/EventB/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v rodin >/dev/null 2>&1 || [[ -d /opt/rodin ]] diff --git a/@ether/library/Language/EventB/install.sh b/@ether/library/Language/EventB/install.sh new file mode 100755 index 00000000..373e85ac --- /dev/null +++ b/@ether/library/Language/EventB/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Event-B (Rodin platform) - https://www.event-b.org/ +# Rodin is an Eclipse-based IDE for Event-B +echo "Event-B uses the Rodin platform (Eclipse-based IDE)." +echo "Download from: https://wiki.event-b.org/index.php/Rodin_Platform_Releases" +echo "Rodin requires a manual download of the Eclipse-based IDE." +if [[ "$(uname)" == "Linux" ]]; then + ARCH=$(uname -m) + echo "Visit https://sourceforge.net/projects/rodin-b-sharp/ to download Rodin for Linux ($ARCH)." +fi diff --git a/@ether/library/Language/EventB/repl.sh b/@ether/library/Language/EventB/repl.sh new file mode 100755 index 00000000..dca1abef --- /dev/null +++ b/@ether/library/Language/EventB/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Event-B uses the Rodin IDE. No command-line REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/EventB/run.sh b/@ether/library/Language/EventB/run.sh new file mode 100755 index 00000000..fecda79a --- /dev/null +++ b/@ether/library/Language/EventB/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Event-B files are used with the Rodin platform. Displaying file:" +cat "$1" diff --git a/@ether/library/Language/FACTORIE/check.sh b/@ether/library/Language/FACTORIE/check.sh new file mode 100755 index 00000000..9bda9fde --- /dev/null +++ b/@ether/library/Language/FACTORIE/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/factorie/factorie" +[[ -d "$REPO_DIR/target" ]] diff --git a/@ether/library/Language/FACTORIE/install.sh b/@ether/library/Language/FACTORIE/install.sh new file mode 100755 index 00000000..9aecad80 --- /dev/null +++ b/@ether/library/Language/FACTORIE/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install FACTORIE - https://github.com/factorie/factorie +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/factorie/factorie" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/factorie/factorie.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v mvn >/dev/null 2>&1; then + mvn compile -DskipTests +else + echo "Maven is required to build FACTORIE." >&2; exit 1 +fi diff --git a/@ether/library/Language/FACTORIE/repl.sh b/@ether/library/Language/FACTORIE/repl.sh new file mode 100755 index 00000000..0327eb17 --- /dev/null +++ b/@ether/library/Language/FACTORIE/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/factorie/factorie" +exec scala -cp "$REPO_DIR/target/classes:$REPO_DIR/target/dependency/*" diff --git a/@ether/library/Language/FACTORIE/run.sh b/@ether/library/Language/FACTORIE/run.sh new file mode 100755 index 00000000..86b559fd --- /dev/null +++ b/@ether/library/Language/FACTORIE/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/factorie/factorie" +exec scala -cp "$REPO_DIR/target/classes:$REPO_DIR/target/dependency/*" "$1" diff --git a/@ether/library/Language/FSharp/check.sh b/@ether/library/Language/FSharp/check.sh new file mode 100755 index 00000000..b4cea5bf --- /dev/null +++ b/@ether/library/Language/FSharp/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v dotnet >/dev/null 2>&1 diff --git a/@ether/library/Language/FSharp/install.sh b/@ether/library/Language/FSharp/install.sh new file mode 100755 index 00000000..600896d3 --- /dev/null +++ b/@ether/library/Language/FSharp/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install F# (via .NET SDK) - https://fsharp.org/ https://dotnet.microsoft.com/download +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask dotnet-sdk +elif command -v apt-get >/dev/null 2>&1; then + # Microsoft official repo - https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu + sudo apt-get update && sudo apt-get install -y dotnet-sdk-8.0 2>/dev/null || { + wget -q https://dot.net/v1/dotnet-install.sh -O /tmp/dotnet-install.sh + chmod +x /tmp/dotnet-install.sh && /tmp/dotnet-install.sh --channel LTS + rm -f /tmp/dotnet-install.sh + } +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y dotnet-sdk-8.0 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm dotnet-sdk +else + wget -q https://dot.net/v1/dotnet-install.sh -O /tmp/dotnet-install.sh + chmod +x /tmp/dotnet-install.sh && /tmp/dotnet-install.sh --channel LTS + rm -f /tmp/dotnet-install.sh +fi diff --git a/@ether/library/Language/FSharp/repl.sh b/@ether/library/Language/FSharp/repl.sh new file mode 100755 index 00000000..b2192519 --- /dev/null +++ b/@ether/library/Language/FSharp/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec dotnet fsi diff --git a/@ether/library/Language/FSharp/run.sh b/@ether/library/Language/FSharp/run.sh new file mode 100755 index 00000000..c625da1d --- /dev/null +++ b/@ether/library/Language/FSharp/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec dotnet fsi "$1" diff --git a/@ether/library/Language/FStar/check.sh b/@ether/library/Language/FStar/check.sh new file mode 100755 index 00000000..20e6cec4 --- /dev/null +++ b/@ether/library/Language/FStar/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v fstar.exe >/dev/null 2>&1 || command -v fstar >/dev/null 2>&1 || [[ -x /opt/fstar/bin/fstar.exe ]] diff --git a/@ether/library/Language/FStar/install.sh b/@ether/library/Language/FStar/install.sh new file mode 100755 index 00000000..539f53fa --- /dev/null +++ b/@ether/library/Language/FStar/install.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install F* - https://github.com/FStarLang/FStar +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/FStarLang/FStar" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/FStarLang/FStar.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make -j"$(nproc)" + exit 0 +fi +# Install via opam +if command -v opam >/dev/null 2>&1; then + eval "$(opam env)" || true + opam install -y fstar +else + # Download binary release + OS=$(uname -s) + if [[ "$OS" == "Linux" ]]; then + PLATFORM="Linux" + elif [[ "$OS" == "Darwin" ]]; then + PLATFORM="macOS" + else + echo "Unsupported OS. Use FROM_SOURCE=true or opam." >&2; exit 1 + fi + VERSION=$(curl -sSL https://api.github.com/repos/FStarLang/FStar/releases/latest | grep tag_name | cut -d'"' -f4) + curl -fsSL "https://github.com/FStarLang/FStar/releases/download/${VERSION}/fstar_${VERSION#v}_${PLATFORM}_x86_64.tar.gz" -o /tmp/fstar.tar.gz + sudo mkdir -p /opt/fstar && sudo tar -C /opt/fstar --strip-components=1 -xzf /tmp/fstar.tar.gz + rm -f /tmp/fstar.tar.gz + sudo ln -sf /opt/fstar/bin/fstar.exe /usr/local/bin/fstar +fi diff --git a/@ether/library/Language/FStar/repl.sh b/@ether/library/Language/FStar/repl.sh new file mode 100755 index 00000000..1911cf64 --- /dev/null +++ b/@ether/library/Language/FStar/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "F* has no interactive REPL. Use: fstar.exe " >&2 +exit 1 diff --git a/@ether/library/Language/FStar/run.sh b/@ether/library/Language/FStar/run.sh new file mode 100755 index 00000000..d8085bdf --- /dev/null +++ b/@ether/library/Language/FStar/run.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v fstar.exe >/dev/null 2>&1; then + exec fstar.exe "$1" +elif command -v fstar >/dev/null 2>&1; then + exec fstar "$1" +elif [[ -x /opt/fstar/bin/fstar.exe ]]; then + exec /opt/fstar/bin/fstar.exe "$1" +else + echo "F* not found." >&2; exit 1 +fi diff --git a/@ether/library/Language/Factor/check.sh b/@ether/library/Language/Factor/check.sh new file mode 100755 index 00000000..d5dcd93a --- /dev/null +++ b/@ether/library/Language/Factor/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v factor-lang >/dev/null 2>&1 || [[ -x /opt/factor/factor ]] diff --git a/@ether/library/Language/Factor/install.sh b/@ether/library/Language/Factor/install.sh new file mode 100755 index 00000000..36f698ac --- /dev/null +++ b/@ether/library/Language/Factor/install.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Factor - https://factorcode.org/ https://github.com/factor/factor +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/factor/factor" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/factor/factor.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make && ./build.sh update + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install factor +elif command -v apt-get >/dev/null 2>&1; then + # Download official binary release + ARCH=$(uname -m) + if [[ "$ARCH" == "x86_64" ]]; then + curl -fsSL "https://downloads.factorcode.org/releases/0.99/factor-linux-x86-64-0.99.tar.gz" -o /tmp/factor.tar.gz + sudo mkdir -p /opt/factor && sudo tar -C /opt/factor --strip-components=1 -xzf /tmp/factor.tar.gz + rm -f /tmp/factor.tar.gz + sudo ln -sf /opt/factor/factor /usr/local/bin/factor-lang + else + echo "Build from source for non-x86_64: FROM_SOURCE=true" >&2; exit 1 + fi +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm factor-lang +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/Factor/repl.sh b/@ether/library/Language/Factor/repl.sh new file mode 100755 index 00000000..4afa5904 --- /dev/null +++ b/@ether/library/Language/Factor/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +if command -v factor-lang >/dev/null 2>&1; then + exec factor-lang +elif [[ -x /opt/factor/factor ]]; then + exec /opt/factor/factor +else + echo "Factor not found." >&2; exit 1 +fi diff --git a/@ether/library/Language/Factor/run.sh b/@ether/library/Language/Factor/run.sh new file mode 100755 index 00000000..0b5fa318 --- /dev/null +++ b/@ether/library/Language/Factor/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v factor-lang >/dev/null 2>&1; then + exec factor-lang -run="$1" +elif [[ -x /opt/factor/factor ]]; then + exec /opt/factor/factor -run="$1" +else + echo "Factor not found." >&2; exit 1 +fi diff --git a/@ether/library/Language/Fe/check.sh b/@ether/library/Language/Fe/check.sh new file mode 100755 index 00000000..34913a55 --- /dev/null +++ b/@ether/library/Language/Fe/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v fe >/dev/null 2>&1 diff --git a/@ether/library/Language/Fe/install.sh b/@ether/library/Language/Fe/install.sh new file mode 100755 index 00000000..370c5f67 --- /dev/null +++ b/@ether/library/Language/Fe/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +# Fe: Ethereum smart contract language - https://fe-lang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ethereum/fe" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ethereum/fe.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + exit 0 +fi +if command -v cargo >/dev/null 2>&1; then + cargo install fe +else + # Download pre-built binary from GitHub releases + OS="$(uname -s | tr '[:upper:]' '[:lower:]')" + ARCH="$(uname -m)" + echo "Download Fe from: https://github.com/ethereum/fe/releases" >&2 + echo "Select the binary for ${OS}-${ARCH}" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Fe/packages.sh b/@ether/library/Language/Fe/packages.sh new file mode 100755 index 00000000..b424279f --- /dev/null +++ b/@ether/library/Language/Fe/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Fe does not have a package manager yet." +echo "https://github.com/ethereum/fe" diff --git a/@ether/library/Language/Fe/repl.sh b/@ether/library/Language/Fe/repl.sh new file mode 100755 index 00000000..e99389a7 --- /dev/null +++ b/@ether/library/Language/Fe/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Fe does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Fe/run.sh b/@ether/library/Language/Fe/run.sh new file mode 100755 index 00000000..bcd7b1c7 --- /dev/null +++ b/@ether/library/Language/Fe/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec fe build "$@" diff --git a/@ether/library/Language/Felix/check.sh b/@ether/library/Language/Felix/check.sh new file mode 100755 index 00000000..edb5090b --- /dev/null +++ b/@ether/library/Language/Felix/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v flx >/dev/null 2>&1 diff --git a/@ether/library/Language/Felix/install.sh b/@ether/library/Language/Felix/install.sh new file mode 100755 index 00000000..688c3c36 --- /dev/null +++ b/@ether/library/Language/Felix/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Felix - https://github.com/felix-lang/felix +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/felix-lang/felix" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/felix-lang/felix.git "$REPO_DIR" +fi +cd "$REPO_DIR" && make build && sudo make install diff --git a/@ether/library/Language/Felix/repl.sh b/@ether/library/Language/Felix/repl.sh new file mode 100755 index 00000000..84ed53ed --- /dev/null +++ b/@ether/library/Language/Felix/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Felix has no interactive REPL. Use: flx " >&2 +exit 1 diff --git a/@ether/library/Language/Felix/run.sh b/@ether/library/Language/Felix/run.sh new file mode 100755 index 00000000..286040f1 --- /dev/null +++ b/@ether/library/Language/Felix/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec flx "$1" diff --git a/@ether/library/Language/Fennel/check.sh b/@ether/library/Language/Fennel/check.sh new file mode 100755 index 00000000..0278854f --- /dev/null +++ b/@ether/library/Language/Fennel/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v fennel >/dev/null 2>&1 diff --git a/@ether/library/Language/Fennel/install.sh b/@ether/library/Language/Fennel/install.sh new file mode 100755 index 00000000..e43692a0 --- /dev/null +++ b/@ether/library/Language/Fennel/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Fennel - https://fennel-lang.org/ https://github.com/bakpakin/Fennel +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/bakpakin/Fennel" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/bakpakin/Fennel.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make && sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install fennel +elif command -v luarocks >/dev/null 2>&1; then + luarocks install fennel +else + # Download standalone script + curl -fsSL https://fennel-lang.org/downloads/fennel-1.4.2 -o /tmp/fennel + chmod +x /tmp/fennel && sudo mv /tmp/fennel /usr/local/bin/fennel +fi diff --git a/@ether/library/Language/Fennel/packages.sh b/@ether/library/Language/Fennel/packages.sh new file mode 100755 index 00000000..0b07e90c --- /dev/null +++ b/@ether/library/Language/Fennel/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Fennel" +REGISTRIES=( + "LuaRocks: https://luarocks.org (Fennel uses the Lua ecosystem)" +) + +show_usage() { + echo "Package manager for $LANG_NAME (uses Lua ecosystem)" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v luarocks &>/dev/null; then + luarocks search "$@" + else + echo "Visit: https://luarocks.org/search?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v luarocks &>/dev/null; then + luarocks show "$1" + else + echo "Visit: https://luarocks.org/modules?q=$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + luarocks install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Fennel/repl.sh b/@ether/library/Language/Fennel/repl.sh new file mode 100755 index 00000000..f8d314b3 --- /dev/null +++ b/@ether/library/Language/Fennel/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec fennel diff --git a/@ether/library/Language/Fennel/run.sh b/@ether/library/Language/Fennel/run.sh new file mode 100755 index 00000000..846434a5 --- /dev/null +++ b/@ether/library/Language/Fennel/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec fennel "$1" diff --git a/@ether/library/Language/Figaro/check.sh b/@ether/library/Language/Figaro/check.sh new file mode 100755 index 00000000..d035d28b --- /dev/null +++ b/@ether/library/Language/Figaro/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/charles-river-analytics/figaro" +[[ -d "$REPO_DIR/target" ]] diff --git a/@ether/library/Language/Figaro/install.sh b/@ether/library/Language/Figaro/install.sh new file mode 100755 index 00000000..990967da --- /dev/null +++ b/@ether/library/Language/Figaro/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Figaro - https://github.com/charles-river-analytics/figaro +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/charles-river-analytics/figaro" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/charles-river-analytics/figaro.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v sbt >/dev/null 2>&1; then + sbt compile +else + echo "sbt is required to build Figaro." >&2; exit 1 +fi diff --git a/@ether/library/Language/Figaro/repl.sh b/@ether/library/Language/Figaro/repl.sh new file mode 100755 index 00000000..6a9452c3 --- /dev/null +++ b/@ether/library/Language/Figaro/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/charles-river-analytics/figaro" +cd "$REPO_DIR" && exec sbt console diff --git a/@ether/library/Language/Figaro/run.sh b/@ether/library/Language/Figaro/run.sh new file mode 100755 index 00000000..f8f5121c --- /dev/null +++ b/@ether/library/Language/Figaro/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/charles-river-analytics/figaro" +cd "$REPO_DIR" && sbt "runMain $1" diff --git a/@ether/library/Language/Fish/check.sh b/@ether/library/Language/Fish/check.sh new file mode 100755 index 00000000..159cfc0d --- /dev/null +++ b/@ether/library/Language/Fish/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +python3 -c "import fish" 2>/dev/null || command -v fish-lang >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/TuxSH/fish-jit" + [[ -d "$REPO_DIR" ]] +} diff --git a/@ether/library/Language/Fish/install.sh b/@ether/library/Language/Fish/install.sh new file mode 100755 index 00000000..8c1decd8 --- /dev/null +++ b/@ether/library/Language/Fish/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install ><> (Fish) esoteric language interpreter +# https://esolangs.org/wiki/Fish +# Using the Python-based interpreter +pip install fish-lang 2>/dev/null || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/TuxSH/fish-jit" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/TuxSH/fish-jit.git "$REPO_DIR" 2>/dev/null || { + # Fallback: download fish.py interpreter directly + mkdir -p "${ETHER_EXTERNAL_DIR:-/tmp}/fish" + curl -fsSL "https://gist.githubusercontent.com/anonymous/6392418/raw/fish.py" -o "${ETHER_EXTERNAL_DIR:-/tmp}/fish/fish.py" 2>/dev/null || true + } + fi +} +echo "><> (Fish) interpreter installed." diff --git a/@ether/library/Language/Fish/repl.sh b/@ether/library/Language/Fish/repl.sh new file mode 100755 index 00000000..82fe1102 --- /dev/null +++ b/@ether/library/Language/Fish/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "><> (Fish) has no interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Fish/run.sh b/@ether/library/Language/Fish/run.sh new file mode 100755 index 00000000..a5baf393 --- /dev/null +++ b/@ether/library/Language/Fish/run.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +# ><> (Fish) esoteric language +if command -v fish-lang >/dev/null 2>&1; then + exec fish-lang "$1" +else + exec python3 -m fish "$1" 2>/dev/null || { + echo "><> (Fish) interpreter not found." >&2; exit 1 + } +fi diff --git a/@ether/library/Language/Flapjax/check.sh b/@ether/library/Language/Flapjax/check.sh new file mode 100755 index 00000000..092d3483 --- /dev/null +++ b/@ether/library/Language/Flapjax/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +npm list flapjax >/dev/null 2>&1 || npm list -g flapjax >/dev/null 2>&1 || command -v node >/dev/null 2>&1 diff --git a/@ether/library/Language/Flapjax/install.sh b/@ether/library/Language/Flapjax/install.sh new file mode 100755 index 00000000..b7048560 --- /dev/null +++ b/@ether/library/Language/Flapjax/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Flapjax - https://www.flapjax-lang.org/ +# Flapjax is a JavaScript library/compiler for FRP +npm install flapjax 2>/dev/null || { + echo "Flapjax can be used via the online compiler at https://www.flapjax-lang.org/" + echo "Or download the library from the website." +} diff --git a/@ether/library/Language/Flapjax/repl.sh b/@ether/library/Language/Flapjax/repl.sh new file mode 100755 index 00000000..3a07e4f6 --- /dev/null +++ b/@ether/library/Language/Flapjax/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec node -e "const flapjax = require('flapjax');" -i 2>/dev/null || exec node diff --git a/@ether/library/Language/Flapjax/run.sh b/@ether/library/Language/Flapjax/run.sh new file mode 100755 index 00000000..f082fff1 --- /dev/null +++ b/@ether/library/Language/Flapjax/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec node "$1" diff --git a/@ether/library/Language/FlatBuffers/check.sh b/@ether/library/Language/FlatBuffers/check.sh new file mode 100755 index 00000000..63cc93d7 --- /dev/null +++ b/@ether/library/Language/FlatBuffers/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v flatc >/dev/null 2>&1 diff --git a/@ether/library/Language/FlatBuffers/install.sh b/@ether/library/Language/FlatBuffers/install.sh new file mode 100755 index 00000000..d94bb461 --- /dev/null +++ b/@ether/library/Language/FlatBuffers/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install FlatBuffers - https://flatbuffers.dev/ https://github.com/google/flatbuffers +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/google/flatbuffers" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/google/flatbuffers.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cmake -S . -B build && cmake --build build -j"$(nproc)" && sudo cmake --install build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install flatbuffers +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y flatbuffers-compiler +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y flatbuffers-compiler +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm flatbuffers +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/FlatBuffers/repl.sh b/@ether/library/Language/FlatBuffers/repl.sh new file mode 100755 index 00000000..e07631d8 --- /dev/null +++ b/@ether/library/Language/FlatBuffers/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "FlatBuffers (flatc) has no interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/FlatBuffers/run.sh b/@ether/library/Language/FlatBuffers/run.sh new file mode 100755 index 00000000..afa580d6 --- /dev/null +++ b/@ether/library/Language/FlatBuffers/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec flatc --gen-all "$1" diff --git a/@ether/library/Language/Flix/check.sh b/@ether/library/Language/Flix/check.sh new file mode 100755 index 00000000..10f98d8b --- /dev/null +++ b/@ether/library/Language/Flix/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v flix >/dev/null 2>&1 || [[ -f "$HOME/.flix/flix.jar" ]] diff --git a/@ether/library/Language/Flix/install.sh b/@ether/library/Language/Flix/install.sh new file mode 100755 index 00000000..caeb0d48 --- /dev/null +++ b/@ether/library/Language/Flix/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Flix - https://flix.dev/ https://github.com/flix/flix +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/flix/flix" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/flix/flix.git "$REPO_DIR" + fi + cd "$REPO_DIR" && gradle build -x test + exit 0 +fi +# Download the Flix jar +VERSION=$(curl -sSL https://api.github.com/repos/flix/flix/releases/latest | grep tag_name | cut -d'"' -f4) +mkdir -p "$HOME/.flix" +curl -fsSL "https://github.com/flix/flix/releases/download/${VERSION}/flix.jar" -o "$HOME/.flix/flix.jar" +echo "Flix installed to $HOME/.flix/flix.jar" +echo "Run with: java -jar $HOME/.flix/flix.jar" diff --git a/@ether/library/Language/Flix/repl.sh b/@ether/library/Language/Flix/repl.sh new file mode 100755 index 00000000..2fc67b55 --- /dev/null +++ b/@ether/library/Language/Flix/repl.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +if command -v flix >/dev/null 2>&1; then + exec flix repl +else + exec java -jar "$HOME/.flix/flix.jar" repl +fi diff --git a/@ether/library/Language/Flix/run.sh b/@ether/library/Language/Flix/run.sh new file mode 100755 index 00000000..e9b361cd --- /dev/null +++ b/@ether/library/Language/Flix/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v flix >/dev/null 2>&1; then + exec flix run "$1" +else + exec java -jar "$HOME/.flix/flix.jar" run "$1" +fi diff --git a/@ether/library/Language/Flutter/check.sh b/@ether/library/Language/Flutter/check.sh new file mode 100755 index 00000000..4d519493 --- /dev/null +++ b/@ether/library/Language/Flutter/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v flutter >/dev/null 2>&1 diff --git a/@ether/library/Language/Flutter/install.sh b/@ether/library/Language/Flutter/install.sh new file mode 100755 index 00000000..9bc9092c --- /dev/null +++ b/@ether/library/Language/Flutter/install.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Flutter - https://flutter.dev/ https://docs.flutter.dev/get-started/install +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/flutter/flutter" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/flutter/flutter.git "$REPO_DIR" + fi + export PATH="$REPO_DIR/bin:$PATH" + flutter doctor + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask flutter +else + # Official: clone the Flutter repo + FLUTTER_DIR="$HOME/.flutter-sdk" + if [[ -d "$FLUTTER_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$FLUTTER_DIR" pull || true + else + GIT_TERMINAL_PROMPT=0 git clone https://github.com/flutter/flutter.git "$FLUTTER_DIR" -b stable + fi + if ! grep -q '.flutter-sdk/bin' "$HOME/.profile" 2>/dev/null; then + echo 'export PATH="$HOME/.flutter-sdk/bin:$PATH"' >> "$HOME/.profile" + fi + export PATH="$FLUTTER_DIR/bin:$PATH" + flutter doctor +fi diff --git a/@ether/library/Language/Flutter/packages.sh b/@ether/library/Language/Flutter/packages.sh new file mode 100755 index 00000000..ae894c5b --- /dev/null +++ b/@ether/library/Language/Flutter/packages.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Flutter" +REGISTRIES=( + "pub.dev: https://pub.dev" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://pub.dev/packages?q=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://pub.dev/packages/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + flutter pub add "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Flutter/repl.sh b/@ether/library/Language/Flutter/repl.sh new file mode 100755 index 00000000..85d3fcfd --- /dev/null +++ b/@ether/library/Language/Flutter/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Flutter has no interactive REPL. Use 'dart' for a Dart REPL or 'flutter run' for app execution." >&2 +exit 1 diff --git a/@ether/library/Language/Flutter/run.sh b/@ether/library/Language/Flutter/run.sh new file mode 100755 index 00000000..4cd13d2c --- /dev/null +++ b/@ether/library/Language/Flutter/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ -d "$1" ]]; then + cd "$1" && flutter run +else + exec dart run "$1" +fi diff --git a/@ether/library/Language/FoCaLize/check.sh b/@ether/library/Language/FoCaLize/check.sh new file mode 100755 index 00000000..fbdd6705 --- /dev/null +++ b/@ether/library/Language/FoCaLize/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v focalizec >/dev/null 2>&1 diff --git a/@ether/library/Language/FoCaLize/install.sh b/@ether/library/Language/FoCaLize/install.sh new file mode 100755 index 00000000..b4683be1 --- /dev/null +++ b/@ether/library/Language/FoCaLize/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install FoCaLize - https://github.com/pessaux-f/focalize +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/pessaux-f/focalize" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/pessaux-f/focalize.git "$REPO_DIR" +fi +cd "$REPO_DIR" && ./configure && make && sudo make install diff --git a/@ether/library/Language/FoCaLize/repl.sh b/@ether/library/Language/FoCaLize/repl.sh new file mode 100755 index 00000000..1c7b5898 --- /dev/null +++ b/@ether/library/Language/FoCaLize/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "FoCaLize has no interactive REPL. Use: focalizec " >&2 +exit 1 diff --git a/@ether/library/Language/FoCaLize/run.sh b/@ether/library/Language/FoCaLize/run.sh new file mode 100755 index 00000000..94eb4efa --- /dev/null +++ b/@ether/library/Language/FoCaLize/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec focalizec "$1" diff --git a/@ether/library/Language/Formality/check.sh b/@ether/library/Language/Formality/check.sh new file mode 100755 index 00000000..d5bee0f7 --- /dev/null +++ b/@ether/library/Language/Formality/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v fm >/dev/null 2>&1 || command -v formality >/dev/null 2>&1 diff --git a/@ether/library/Language/Formality/install.sh b/@ether/library/Language/Formality/install.sh new file mode 100755 index 00000000..a605e3ad --- /dev/null +++ b/@ether/library/Language/Formality/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Formality - https://github.com/moonad/Formality +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/moonad/Formality" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/moonad/Formality.git "$REPO_DIR" +fi +cd "$REPO_DIR" +npm install 2>/dev/null || true +npm link 2>/dev/null || true diff --git a/@ether/library/Language/Formality/repl.sh b/@ether/library/Language/Formality/repl.sh new file mode 100755 index 00000000..222760f9 --- /dev/null +++ b/@ether/library/Language/Formality/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Formality has no interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Formality/run.sh b/@ether/library/Language/Formality/run.sh new file mode 100755 index 00000000..6d71c399 --- /dev/null +++ b/@ether/library/Language/Formality/run.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v fm >/dev/null 2>&1; then + exec fm "$1" +elif command -v formality >/dev/null 2>&1; then + exec formality "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/moonad/Formality" + exec node "$REPO_DIR/bin/fm.js" "$1" +fi diff --git a/@ether/library/Language/Forth/check.sh b/@ether/library/Language/Forth/check.sh new file mode 100755 index 00000000..7463f07f --- /dev/null +++ b/@ether/library/Language/Forth/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v gforth >/dev/null 2>&1 diff --git a/@ether/library/Language/Forth/install.sh b/@ether/library/Language/Forth/install.sh new file mode 100755 index 00000000..1520c09f --- /dev/null +++ b/@ether/library/Language/Forth/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Forth (gforth) - https://forth-standard.org/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install gforth +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gforth +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gforth +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gforth +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Forth/repl.sh b/@ether/library/Language/Forth/repl.sh new file mode 100755 index 00000000..d5359521 --- /dev/null +++ b/@ether/library/Language/Forth/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec gforth diff --git a/@ether/library/Language/Forth/run.sh b/@ether/library/Language/Forth/run.sh new file mode 100755 index 00000000..93a08715 --- /dev/null +++ b/@ether/library/Language/Forth/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gforth "$1" -e bye diff --git a/@ether/library/Language/Fortran/check.sh b/@ether/library/Language/Fortran/check.sh new file mode 100755 index 00000000..c0f9874b --- /dev/null +++ b/@ether/library/Language/Fortran/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v gfortran >/dev/null 2>&1 diff --git a/@ether/library/Language/Fortran/install.sh b/@ether/library/Language/Fortran/install.sh new file mode 100755 index 00000000..f6b1d5de --- /dev/null +++ b/@ether/library/Language/Fortran/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Fortran (gfortran) - https://fortran-lang.org/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install gcc +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gfortran +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gcc-gfortran +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gcc-fortran +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Fortran/packages.sh b/@ether/library/Language/Fortran/packages.sh new file mode 100755 index 00000000..6291cf9f --- /dev/null +++ b/@ether/library/Language/Fortran/packages.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRIES=( + "https://fortran-lang.org/packages/" + "https://github.com/fortran-lang/fpm-registry" +) + +usage() { + echo "Fortran Package Registries:" + for url in "${REGISTRIES[@]}"; do echo " $url"; done + echo + echo "Usage: packages.sh {search|info|install} " +} + +cmd_search() { + local q="$1" + if command -v fpm &>/dev/null; then + fpm list "$q" + else + echo "https://fortran-lang.org/packages/?q=$q" + echo "https://github.com/fortran-lang/fpm-registry/search?q=$q" + fi +} + +cmd_info() { + local pkg="$1" + echo "https://fortran-lang.org/packages/$pkg/" + echo "https://github.com/fortran-lang/$pkg" +} + +cmd_install() { + local pkg="$1" + if command -v fpm &>/dev/null; then + echo "Adding via fpm..." + fpm add "$pkg" + else + echo "Install fpm (Fortran Package Manager) first:" + echo " https://fpm.fortran-lang.org/install/" + echo + echo "Then run:" + echo " fpm add $pkg" + echo + echo "Or add to fpm.toml:" + echo " [dependencies]" + echo " $pkg = { git = \"https://github.com/OWNER/$pkg.git\" }" + fi +} + +case "${1:-}" in + search) shift; cmd_search "$1" ;; + info) shift; cmd_info "$1" ;; + install) shift; cmd_install "$1" ;; + *) usage ;; +esac diff --git a/@ether/library/Language/Fortran/repl.sh b/@ether/library/Language/Fortran/repl.sh new file mode 100755 index 00000000..3426764c --- /dev/null +++ b/@ether/library/Language/Fortran/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Fortran has no interactive REPL. Use: gfortran -o out && ./out" >&2 +exit 1 diff --git a/@ether/library/Language/Fortran/run.sh b/@ether/library/Language/Fortran/run.sh new file mode 100755 index 00000000..ddf523b9 --- /dev/null +++ b/@ether/library/Language/Fortran/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +gfortran "$1" -o /tmp/fortran_out && /tmp/fortran_out diff --git a/@ether/library/Language/Fractran/check.sh b/@ether/library/Language/Fractran/check.sh new file mode 100755 index 00000000..70b921e6 --- /dev/null +++ b/@ether/library/Language/Fractran/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import fractran" 2>/dev/null || [[ -f "${ETHER_EXTERNAL_DIR:-/tmp}/fractran/fractran.py" ]] diff --git a/@ether/library/Language/Fractran/install.sh b/@ether/library/Language/Fractran/install.sh new file mode 100755 index 00000000..29844073 --- /dev/null +++ b/@ether/library/Language/Fractran/install.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail +# FRACTRAN is an esoteric language by John Conway. +# https://esolangs.org/wiki/FRACTRAN +# Install a Python-based interpreter +pip install fractran 2>/dev/null || { + # Create a minimal FRACTRAN interpreter + mkdir -p "${ETHER_EXTERNAL_DIR:-/tmp}/fractran" + cat > "${ETHER_EXTERNAL_DIR:-/tmp}/fractran/fractran.py" << 'PYEOF' +#!/usr/bin/env python3 +import sys +from fractions import Fraction + +def run_fractran(program, n, max_steps=10000): + fractions = [] + for token in program.strip().split(): + if '/' in token: + num, den = token.split('/') + fractions.append(Fraction(int(num), int(den))) + for _ in range(max_steps): + found = False + for f in fractions: + result = n * f + if result.denominator == 1: + n = int(result) + print(n) + found = True + break + if not found: + break + return n + +if __name__ == '__main__': + with open(sys.argv[1]) as f: + lines = f.read().strip().split('\n') + program = lines[0] + n = int(lines[1]) if len(lines) > 1 else 2 + run_fractran(program, n) +PYEOF + chmod +x "${ETHER_EXTERNAL_DIR:-/tmp}/fractran/fractran.py" + echo "FRACTRAN interpreter installed to ${ETHER_EXTERNAL_DIR:-/tmp}/fractran/fractran.py" +} diff --git a/@ether/library/Language/Fractran/repl.sh b/@ether/library/Language/Fractran/repl.sh new file mode 100755 index 00000000..724faf77 --- /dev/null +++ b/@ether/library/Language/Fractran/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "FRACTRAN has no interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Fractran/run.sh b/@ether/library/Language/Fractran/run.sh new file mode 100755 index 00000000..8cf6aa7f --- /dev/null +++ b/@ether/library/Language/Fractran/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if python3 -c "import fractran" 2>/dev/null; then + exec python3 -m fractran "$1" +else + exec python3 "${ETHER_EXTERNAL_DIR:-/tmp}/fractran/fractran.py" "$1" +fi diff --git a/@ether/library/Language/Frege/check.sh b/@ether/library/Language/Frege/check.sh new file mode 100755 index 00000000..df30c85c --- /dev/null +++ b/@ether/library/Language/Frege/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +[[ -f "$HOME/.frege/frege.jar" ]] || command -v frege >/dev/null 2>&1 diff --git a/@ether/library/Language/Frege/install.sh b/@ether/library/Language/Frege/install.sh new file mode 100755 index 00000000..4d814fe7 --- /dev/null +++ b/@ether/library/Language/Frege/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Frege - https://github.com/Frege/frege +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Frege/frege" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Frege/frege.git "$REPO_DIR" +fi +# Download the Frege compiler jar +mkdir -p "$HOME/.frege" +VERSION="3.25.84" +curl -fsSL "https://github.com/Frege/frege/releases/download/${VERSION}/frege${VERSION}.jar" -o "$HOME/.frege/frege.jar" 2>/dev/null || { + cd "$REPO_DIR" && ./gradlew build -x test +} +echo "Frege installed." diff --git a/@ether/library/Language/Frege/repl.sh b/@ether/library/Language/Frege/repl.sh new file mode 100755 index 00000000..764166c5 --- /dev/null +++ b/@ether/library/Language/Frege/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +FREGE_JAR="$HOME/.frege/frege.jar" +exec java -cp "$FREGE_JAR" frege.repl.FregeRepl diff --git a/@ether/library/Language/Frege/run.sh b/@ether/library/Language/Frege/run.sh new file mode 100755 index 00000000..6d665343 --- /dev/null +++ b/@ether/library/Language/Frege/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +FREGE_JAR="$HOME/.frege/frege.jar" +java -cp "$FREGE_JAR" frege.compiler.Main "$1" && java -cp ".:$FREGE_JAR" "$(basename "${1%.fr}")" diff --git a/@ether/library/Language/FunC/check.sh b/@ether/library/Language/FunC/check.sh new file mode 100755 index 00000000..9a9da2b0 --- /dev/null +++ b/@ether/library/Language/FunC/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v func >/dev/null 2>&1 diff --git a/@ether/library/Language/FunC/install.sh b/@ether/library/Language/FunC/install.sh new file mode 100755 index 00000000..520a803d --- /dev/null +++ b/@ether/library/Language/FunC/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# FunC: TON blockchain low-level smart contract language - https://docs.ton.org/develop/func/overview +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ton-blockchain/ton" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone --recursive https://github.com/ton-blockchain/ton.git "$REPO_DIR" +fi +cd "$REPO_DIR" && mkdir -p build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make -j"$(nproc)" func diff --git a/@ether/library/Language/FunC/packages.sh b/@ether/library/Language/FunC/packages.sh new file mode 100755 index 00000000..2deb399d --- /dev/null +++ b/@ether/library/Language/FunC/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "FunC does not have a package manager." +echo "TON smart contracts: https://github.com/ton-blockchain" diff --git a/@ether/library/Language/FunC/repl.sh b/@ether/library/Language/FunC/repl.sh new file mode 100755 index 00000000..c52bd8af --- /dev/null +++ b/@ether/library/Language/FunC/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "FunC does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/FunC/run.sh b/@ether/library/Language/FunC/run.sh new file mode 100755 index 00000000..d359fe6e --- /dev/null +++ b/@ether/library/Language/FunC/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec func "$@" diff --git a/@ether/library/Language/Futhark/check.sh b/@ether/library/Language/Futhark/check.sh new file mode 100755 index 00000000..849465b2 --- /dev/null +++ b/@ether/library/Language/Futhark/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v futhark >/dev/null 2>&1 diff --git a/@ether/library/Language/Futhark/install.sh b/@ether/library/Language/Futhark/install.sh new file mode 100755 index 00000000..ef4d2e3a --- /dev/null +++ b/@ether/library/Language/Futhark/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Futhark - https://futhark-lang.org/ https://github.com/diku-dk/futhark +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/diku-dk/futhark" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/diku-dk/futhark.git "$REPO_DIR" + fi + cd "$REPO_DIR" && stack install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install futhark +elif command -v cabal >/dev/null 2>&1; then + cabal update && cabal install futhark +elif command -v stack >/dev/null 2>&1; then + stack install futhark +else + echo "Install Haskell Stack or cabal first." >&2; exit 1 +fi diff --git a/@ether/library/Language/Futhark/repl.sh b/@ether/library/Language/Futhark/repl.sh new file mode 100755 index 00000000..3483aadf --- /dev/null +++ b/@ether/library/Language/Futhark/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec futhark repl diff --git a/@ether/library/Language/Futhark/run.sh b/@ether/library/Language/Futhark/run.sh new file mode 100755 index 00000000..0ab5eec5 --- /dev/null +++ b/@ether/library/Language/Futhark/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec futhark run "$1" diff --git a/@ether/library/Language/GAP/check.sh b/@ether/library/Language/GAP/check.sh new file mode 100755 index 00000000..b58eefa9 --- /dev/null +++ b/@ether/library/Language/GAP/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v gap >/dev/null 2>&1 diff --git a/@ether/library/Language/GAP/install.sh b/@ether/library/Language/GAP/install.sh new file mode 100755 index 00000000..c290386f --- /dev/null +++ b/@ether/library/Language/GAP/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install GAP - https://www.gap-system.org/ https://github.com/gap-system/gap +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/gap-system/gap" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/gap-system/gap.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./autogen.sh && ./configure && make -j"$(nproc)" + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install gap +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gap +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gap +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gap +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/GAP/repl.sh b/@ether/library/Language/GAP/repl.sh new file mode 100755 index 00000000..58db77ae --- /dev/null +++ b/@ether/library/Language/GAP/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec gap diff --git a/@ether/library/Language/GAP/run.sh b/@ether/library/Language/GAP/run.sh new file mode 100755 index 00000000..353d8b97 --- /dev/null +++ b/@ether/library/Language/GAP/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gap "$1" diff --git a/@ether/library/Language/GDScript/check.sh b/@ether/library/Language/GDScript/check.sh new file mode 100755 index 00000000..f0f07139 --- /dev/null +++ b/@ether/library/Language/GDScript/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v godot >/dev/null 2>&1 diff --git a/@ether/library/Language/GDScript/install.sh b/@ether/library/Language/GDScript/install.sh new file mode 100755 index 00000000..12c362f2 --- /dev/null +++ b/@ether/library/Language/GDScript/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# GDScript - Godot Engine +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask godot +elif command -v apt-get >/dev/null 2>&1; then + echo "Install Godot via snap or download from https://godotengine.org/download" >&2 + if command -v snap >/dev/null 2>&1; then + sudo snap install godot-4 + else + echo "snap not available. Download from https://godotengine.org/download" >&2; exit 1 + fi +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y godot +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm godot +else + echo "Download Godot from https://godotengine.org/download" >&2; exit 1 +fi diff --git a/@ether/library/Language/GDScript/packages.sh b/@ether/library/Language/GDScript/packages.sh new file mode 100755 index 00000000..6dac7df3 --- /dev/null +++ b/@ether/library/Language/GDScript/packages.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://godotengine.org/asset-library/asset" + +usage() { + echo "GDScript Package Manager (Godot Asset Library)" + echo "" + echo "Registry: $REGISTRY" + echo "" + echo "Usage: packages.sh [args]" + echo "" + echo "Commands:" + echo " search Search for assets" + echo " info Show asset information" + echo " install Install an asset" +} + +cmd_search() { + local query="$1" + echo "Search Godot Asset Library:" + echo " $REGISTRY?filter=$query" +} + +cmd_info() { + local asset="$1" + echo "Asset info:" + echo " $REGISTRY?filter=$asset" + echo "" + echo "Or search by ID:" + echo " $REGISTRY/$asset" +} + +cmd_install() { + local asset="$1" + echo "Install from Godot Editor > AssetLib tab, or download from:" + echo " $REGISTRY?filter=$asset" + echo "" + echo "Alternatively, download and extract into your project's addons/ directory." +} + +case "${1:-}" in + search) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh search "; exit 1; } + cmd_search "$1" + ;; + info) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh info "; exit 1; } + cmd_info "$1" + ;; + install) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh install "; exit 1; } + cmd_install "$1" + ;; + *) + usage + ;; +esac diff --git a/@ether/library/Language/GDScript/repl.sh b/@ether/library/Language/GDScript/repl.sh new file mode 100755 index 00000000..436a0004 --- /dev/null +++ b/@ether/library/Language/GDScript/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "GDScript runs within the Godot editor. Launch with: godot" diff --git a/@ether/library/Language/GDScript/run.sh b/@ether/library/Language/GDScript/run.sh new file mode 100755 index 00000000..e9e87cd9 --- /dev/null +++ b/@ether/library/Language/GDScript/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec godot --headless --script "$@" diff --git a/@ether/library/Language/GLSL/check.sh b/@ether/library/Language/GLSL/check.sh new file mode 100755 index 00000000..707e8ade --- /dev/null +++ b/@ether/library/Language/GLSL/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v glslangValidator >/dev/null 2>&1 diff --git a/@ether/library/Language/GLSL/install.sh b/@ether/library/Language/GLSL/install.sh new file mode 100755 index 00000000..bf67eb0a --- /dev/null +++ b/@ether/library/Language/GLSL/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing glslang from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/KhronosGroup/glslang" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/KhronosGroup/glslang.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$HOME/.local" && cmake --build build -j"$(nproc)" && cmake --install build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install glslang +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y glslang-tools +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y glslang +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm glslang +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/GLSL/repl.sh b/@ether/library/Language/GLSL/repl.sh new file mode 100755 index 00000000..558510e1 --- /dev/null +++ b/@ether/library/Language/GLSL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "GLSL is a shader language and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/GLSL/run.sh b/@ether/library/Language/GLSL/run.sh new file mode 100755 index 00000000..7f625be9 --- /dev/null +++ b/@ether/library/Language/GLSL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec glslangValidator "$1" diff --git a/@ether/library/Language/GP/check.sh b/@ether/library/Language/GP/check.sh new file mode 100755 index 00000000..cb2ea7f6 --- /dev/null +++ b/@ether/library/Language/GP/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v gp >/dev/null 2>&1 diff --git a/@ether/library/Language/GP/install.sh b/@ether/library/Language/GP/install.sh new file mode 100755 index 00000000..c6064fe7 --- /dev/null +++ b/@ether/library/Language/GP/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing PARI/GP from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ArtificialQualia/pari" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://pari.math.u-bordeaux.fr/git/pari.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./Configure --prefix="$HOME/.local" && make -j"$(nproc)" && make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install pari +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y pari-gp +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y pari-gp +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm pari +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/GP/repl.sh b/@ether/library/Language/GP/repl.sh new file mode 100755 index 00000000..691353f5 --- /dev/null +++ b/@ether/library/Language/GP/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gp diff --git a/@ether/library/Language/GP/run.sh b/@ether/library/Language/GP/run.sh new file mode 100755 index 00000000..eee6e762 --- /dev/null +++ b/@ether/library/Language/GP/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gp -q "$1" diff --git a/@ether/library/Language/GP2/check.sh b/@ether/library/Language/GP2/check.sh new file mode 100755 index 00000000..c262ffab --- /dev/null +++ b/@ether/library/Language/GP2/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/UoYCS-plasma/GP2" +[[ -d "$REPO_DIR" ]] && command -v gp2 >/dev/null 2>&1 || [[ -x "$REPO_DIR/bin/gp2" ]] diff --git a/@ether/library/Language/GP2/install.sh b/@ether/library/Language/GP2/install.sh new file mode 100755 index 00000000..50fa5564 --- /dev/null +++ b/@ether/library/Language/GP2/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing GP2 from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/UoYCS-plasma/GP2" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/UoYCS-plasma/GP2.git "$REPO_DIR" +fi +cd "$REPO_DIR" && make -j"$(nproc)" +echo "GP2 built in $REPO_DIR" diff --git a/@ether/library/Language/GP2/repl.sh b/@ether/library/Language/GP2/repl.sh new file mode 100755 index 00000000..d619b876 --- /dev/null +++ b/@ether/library/Language/GP2/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "GP2 does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/GP2/run.sh b/@ether/library/Language/GP2/run.sh new file mode 100755 index 00000000..4ab7f879 --- /dev/null +++ b/@ether/library/Language/GP2/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/UoYCS-plasma/GP2" +if command -v gp2 >/dev/null 2>&1; then + exec gp2 "$1" +else + exec "$REPO_DIR/bin/gp2" "$1" +fi diff --git a/@ether/library/Language/GReAT/check.sh b/@ether/library/Language/GReAT/check.sh new file mode 100755 index 00000000..511401e5 --- /dev/null +++ b/@ether/library/Language/GReAT/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# GReAT has no standalone CLI command to check. +exit 1 diff --git a/@ether/library/Language/GReAT/install.sh b/@ether/library/Language/GReAT/install.sh new file mode 100755 index 00000000..2c77dac9 --- /dev/null +++ b/@ether/library/Language/GReAT/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# GReAT (Graph Rewriting and Transformation) is an academic tool from Vanderbilt ISIS. +# It runs as an Eclipse/GME plugin and has no standalone CLI installer. +echo "GReAT is distributed as part of the GME (Generic Modeling Environment) toolkit." +echo "Visit: https://archive.isis.vanderbilt.edu/tools/GReAT" +echo "Manual installation required." >&2 +exit 1 diff --git a/@ether/library/Language/GReAT/repl.sh b/@ether/library/Language/GReAT/repl.sh new file mode 100755 index 00000000..22cc0bab --- /dev/null +++ b/@ether/library/Language/GReAT/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "GReAT does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/GReAT/run.sh b/@ether/library/Language/GReAT/run.sh new file mode 100755 index 00000000..f83dd908 --- /dev/null +++ b/@ether/library/Language/GReAT/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "GReAT requires the GME toolkit to execute. Cannot run standalone." >&2 +exit 1 diff --git a/@ether/library/Language/Gamble/check.sh b/@ether/library/Language/Gamble/check.sh new file mode 100755 index 00000000..d0c96ab3 --- /dev/null +++ b/@ether/library/Language/Gamble/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v racket >/dev/null 2>&1 && racket -e '(require gamble)' 2>/dev/null diff --git a/@ether/library/Language/Gamble/install.sh b/@ether/library/Language/Gamble/install.sh new file mode 100755 index 00000000..7cd9fbd8 --- /dev/null +++ b/@ether/library/Language/Gamble/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Gamble - https://github.com/rmculpepper/gamble +# Gamble is a Racket package for probabilistic programming +if command -v raco >/dev/null 2>&1; then + raco pkg install --auto gamble +else + echo "Racket is required. Install Racket first, then: raco pkg install gamble" >&2; exit 1 +fi diff --git a/@ether/library/Language/Gamble/repl.sh b/@ether/library/Language/Gamble/repl.sh new file mode 100755 index 00000000..e60b9506 --- /dev/null +++ b/@ether/library/Language/Gamble/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec racket -l gamble -i diff --git a/@ether/library/Language/Gamble/run.sh b/@ether/library/Language/Gamble/run.sh new file mode 100755 index 00000000..c5cc48f2 --- /dev/null +++ b/@ether/library/Language/Gamble/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec racket "$1" diff --git a/@ether/library/Language/Gen/check.sh b/@ether/library/Language/Gen/check.sh new file mode 100755 index 00000000..ef113449 --- /dev/null +++ b/@ether/library/Language/Gen/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v julia >/dev/null 2>&1 && julia -e 'using Gen' 2>/dev/null diff --git a/@ether/library/Language/Gen/install.sh b/@ether/library/Language/Gen/install.sh new file mode 100755 index 00000000..acd5f935 --- /dev/null +++ b/@ether/library/Language/Gen/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install Gen.jl - https://www.gen.dev/ https://github.com/probcomp/Gen.jl +# Gen is a Julia package for probabilistic programming +if command -v julia >/dev/null 2>&1; then + julia -e 'using Pkg; Pkg.add("Gen")' +else + echo "Julia is required. Install Julia first, then: julia -e 'using Pkg; Pkg.add(\"Gen\")'" >&2; exit 1 +fi diff --git a/@ether/library/Language/Gen/repl.sh b/@ether/library/Language/Gen/repl.sh new file mode 100755 index 00000000..7fe6eb0a --- /dev/null +++ b/@ether/library/Language/Gen/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec julia -e 'using Gen; println("Gen.jl loaded")' -i diff --git a/@ether/library/Language/Gen/run.sh b/@ether/library/Language/Gen/run.sh new file mode 100755 index 00000000..df6a60d7 --- /dev/null +++ b/@ether/library/Language/Gen/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec julia "$1" diff --git a/@ether/library/Language/Gleam/check.sh b/@ether/library/Language/Gleam/check.sh new file mode 100755 index 00000000..9fd2da33 --- /dev/null +++ b/@ether/library/Language/Gleam/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v gleam >/dev/null 2>&1 diff --git a/@ether/library/Language/Gleam/install.sh b/@ether/library/Language/Gleam/install.sh new file mode 100755 index 00000000..ab5ed9bf --- /dev/null +++ b/@ether/library/Language/Gleam/install.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Gleam from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/gleam-lang/gleam" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/gleam-lang/gleam.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release && cp target/release/gleam "$HOME/.local/bin/" + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install gleam +elif command -v apt-get >/dev/null 2>&1; then + # Official: install via prebuilt binaries from GitHub releases + ARCH=$(uname -m) + case "$ARCH" in + x86_64) GLEAM_ARCH="x86_64-unknown-linux-musl" ;; + aarch64) GLEAM_ARCH="aarch64-unknown-linux-musl" ;; + *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; + esac + VERSION=$(curl -sSL https://api.github.com/repos/gleam-lang/gleam/releases/latest | grep '"tag_name"' | sed 's/.*"v\(.*\)".*/\1/') + curl -fsSL "https://github.com/gleam-lang/gleam/releases/download/v${VERSION}/gleam-v${VERSION}-${GLEAM_ARCH}.tar.gz" -o /tmp/gleam.tar.gz + sudo tar -xzf /tmp/gleam.tar.gz -C /usr/local/bin/ + rm -f /tmp/gleam.tar.gz +elif command -v dnf >/dev/null 2>&1; then + ARCH=$(uname -m) + case "$ARCH" in + x86_64) GLEAM_ARCH="x86_64-unknown-linux-musl" ;; + aarch64) GLEAM_ARCH="aarch64-unknown-linux-musl" ;; + *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; + esac + VERSION=$(curl -sSL https://api.github.com/repos/gleam-lang/gleam/releases/latest | grep '"tag_name"' | sed 's/.*"v\(.*\)".*/\1/') + curl -fsSL "https://github.com/gleam-lang/gleam/releases/download/v${VERSION}/gleam-v${VERSION}-${GLEAM_ARCH}.tar.gz" -o /tmp/gleam.tar.gz + sudo tar -xzf /tmp/gleam.tar.gz -C /usr/local/bin/ + rm -f /tmp/gleam.tar.gz +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gleam +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Gleam/packages.sh b/@ether/library/Language/Gleam/packages.sh new file mode 100755 index 00000000..f7dd79b8 --- /dev/null +++ b/@ether/library/Language/Gleam/packages.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Gleam" +REGISTRIES=( + "Hex (Gleam): https://hex.pm" + "Gleam Packages: https://packages.gleam.run" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v gleam &>/dev/null; then + gleam hex search "$@" 2>/dev/null || echo "Visit: https://hex.pm/packages?search=$1" + else + echo "Visit: https://hex.pm/packages?search=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://hex.pm/packages/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + gleam add "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Gleam/repl.sh b/@ether/library/Language/Gleam/repl.sh new file mode 100755 index 00000000..436f69ed --- /dev/null +++ b/@ether/library/Language/Gleam/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gleam shell diff --git a/@ether/library/Language/Gleam/run.sh b/@ether/library/Language/Gleam/run.sh new file mode 100755 index 00000000..ba12c08d --- /dev/null +++ b/@ether/library/Language/Gleam/run.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +if [[ -d "$file" ]]; then + cd "$file" && gleam run +else + dir=$(mktemp -d) + cd "$dir" && gleam new tmp_project --name main >/dev/null 2>&1 + cp "$file" "$dir/tmp_project/src/main.gleam" + cd "$dir/tmp_project" && gleam run + rm -rf "$dir" +fi diff --git a/@ether/library/Language/Gluon/check.sh b/@ether/library/Language/Gluon/check.sh new file mode 100755 index 00000000..f30b7891 --- /dev/null +++ b/@ether/library/Language/Gluon/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v gluon >/dev/null 2>&1 diff --git a/@ether/library/Language/Gluon/install.sh b/@ether/library/Language/Gluon/install.sh new file mode 100755 index 00000000..d049bfe0 --- /dev/null +++ b/@ether/library/Language/Gluon/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# Gluon - statically typed, functional programming language +if command -v cargo >/dev/null 2>&1; then + cargo install gluon_cli +else + echo "Rust/cargo is required. Install Rust first: https://rustup.rs/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Gluon/packages.sh b/@ether/library/Language/Gluon/packages.sh new file mode 100755 index 00000000..ee44d65a --- /dev/null +++ b/@ether/library/Language/Gluon/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Gluon does not have a standard package manager." +echo "https://github.com/gluon-lang/gluon" diff --git a/@ether/library/Language/Gluon/repl.sh b/@ether/library/Language/Gluon/repl.sh new file mode 100755 index 00000000..92dd6d7f --- /dev/null +++ b/@ether/library/Language/Gluon/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gluon -i diff --git a/@ether/library/Language/Gluon/run.sh b/@ether/library/Language/Gluon/run.sh new file mode 100755 index 00000000..fed184a3 --- /dev/null +++ b/@ether/library/Language/Gluon/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gluon "$@" diff --git a/@ether/library/Language/Go/check.sh b/@ether/library/Language/Go/check.sh new file mode 100755 index 00000000..a3d5a313 --- /dev/null +++ b/@ether/library/Language/Go/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v go >/dev/null 2>&1 diff --git a/@ether/library/Language/Go/install.sh b/@ether/library/Language/Go/install.sh new file mode 100755 index 00000000..abc1233f --- /dev/null +++ b/@ether/library/Language/Go/install.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/golang/go" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/golang/go.git "$REPO_DIR" + fi + cd "$REPO_DIR/src" && ./all.bash + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install go +else + # Official method: download tarball from go.dev (https://go.dev/doc/install) + GOVERSION=$(curl -sSL 'https://go.dev/VERSION?m=text' | head -1) + ARCH=$(uname -m) + case "$ARCH" in + x86_64) GOARCH="amd64" ;; + aarch64) GOARCH="arm64" ;; + armv*) GOARCH="armv6l" ;; + *) GOARCH="amd64" ;; + esac + curl -fsSL "https://go.dev/dl/${GOVERSION}.linux-${GOARCH}.tar.gz" -o /tmp/go.tar.gz + sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf /tmp/go.tar.gz + rm -f /tmp/go.tar.gz + # Add to PATH if not already there + if ! grep -q '/usr/local/go/bin' "$HOME/.profile" 2>/dev/null; then + echo 'export PATH=$PATH:/usr/local/go/bin' >> "$HOME/.profile" + fi + export PATH=$PATH:/usr/local/go/bin +fi diff --git a/@ether/library/Language/Go/packages.sh b/@ether/library/Language/Go/packages.sh new file mode 100755 index 00000000..bfa9dddb --- /dev/null +++ b/@ether/library/Language/Go/packages.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Go" +REGISTRIES=( + "pkg.go.dev: https://pkg.go.dev" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://pkg.go.dev/search?q=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + go list -m -json "$1"@latest 2>/dev/null || echo "Visit: https://pkg.go.dev/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + go install "$1"@latest + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Go/repl.sh b/@ether/library/Language/Go/repl.sh new file mode 100755 index 00000000..b06d6a61 --- /dev/null +++ b/@ether/library/Language/Go/repl.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v gore >/dev/null 2>&1; then + exec gore "$@" +elif command -v yaegi >/dev/null 2>&1; then + exec yaegi "$@" +else + echo "No Go REPL found." + echo "Install gore: go install github.com/x-motemen/gore/cmd/gore@latest" + echo "Install yaegi: go install github.com/traefik/yaegi/cmd/yaegi@latest" + exit 1 +fi diff --git a/@ether/library/Language/Go/run.sh b/@ether/library/Language/Go/run.sh new file mode 100755 index 00000000..f3065825 --- /dev/null +++ b/@ether/library/Language/Go/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec go run "$@" diff --git a/@ether/library/Language/GolfScript/check.sh b/@ether/library/Language/GolfScript/check.sh new file mode 100755 index 00000000..8e3e7c7d --- /dev/null +++ b/@ether/library/Language/GolfScript/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/rkoeninger/GolfScript" +[[ -f "$REPO_DIR/golfscript.rb" ]] && command -v ruby >/dev/null 2>&1 diff --git a/@ether/library/Language/GolfScript/install.sh b/@ether/library/Language/GolfScript/install.sh new file mode 100755 index 00000000..cf0a2a3e --- /dev/null +++ b/@ether/library/Language/GolfScript/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing GolfScript from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/rkoeninger/GolfScript" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/rkoeninger/GolfScript.git "$REPO_DIR" +fi +echo "GolfScript cloned to $REPO_DIR. Requires Ruby to run." +# Ensure Ruby is available +command -v ruby >/dev/null 2>&1 || { + echo "Ruby is required to run GolfScript. Please install Ruby first." >&2 + exit 1 +} diff --git a/@ether/library/Language/GolfScript/repl.sh b/@ether/library/Language/GolfScript/repl.sh new file mode 100755 index 00000000..a4492568 --- /dev/null +++ b/@ether/library/Language/GolfScript/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/rkoeninger/GolfScript" +exec ruby "$REPO_DIR/golfscript.rb" diff --git a/@ether/library/Language/GolfScript/run.sh b/@ether/library/Language/GolfScript/run.sh new file mode 100755 index 00000000..eb84cc2e --- /dev/null +++ b/@ether/library/Language/GolfScript/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/rkoeninger/GolfScript" +exec ruby "$REPO_DIR/golfscript.rb" "$1" diff --git a/@ether/library/Language/Grain/check.sh b/@ether/library/Language/Grain/check.sh new file mode 100755 index 00000000..40b5512c --- /dev/null +++ b/@ether/library/Language/Grain/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v grain >/dev/null 2>&1 diff --git a/@ether/library/Language/Grain/install.sh b/@ether/library/Language/Grain/install.sh new file mode 100755 index 00000000..5200ab31 --- /dev/null +++ b/@ether/library/Language/Grain/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Grain from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/grain-lang/grain" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/grain-lang/grain.git "$REPO_DIR" + fi + cd "$REPO_DIR" && npm install && npm run build + exit 0 +fi +# Official install via npm (https://grain-lang.org/docs/getting_grain) +if command -v npm >/dev/null 2>&1; then + npm install -g @grain/cli +else + echo "npm is required to install Grain. Install Node.js first." >&2 + exit 1 +fi diff --git a/@ether/library/Language/Grain/repl.sh b/@ether/library/Language/Grain/repl.sh new file mode 100755 index 00000000..804df0ec --- /dev/null +++ b/@ether/library/Language/Grain/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Grain does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Grain/run.sh b/@ether/library/Language/Grain/run.sh new file mode 100755 index 00000000..b131ae35 --- /dev/null +++ b/@ether/library/Language/Grain/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec grain run "$1" diff --git a/@ether/library/Language/Granule/check.sh b/@ether/library/Language/Granule/check.sh new file mode 100755 index 00000000..c47f30bf --- /dev/null +++ b/@ether/library/Language/Granule/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v gr >/dev/null 2>&1 || command -v granule >/dev/null 2>&1 diff --git a/@ether/library/Language/Granule/install.sh b/@ether/library/Language/Granule/install.sh new file mode 100755 index 00000000..f5a366b7 --- /dev/null +++ b/@ether/library/Language/Granule/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Granule from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/granule-project/granule" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/granule-project/granule.git "$REPO_DIR" +fi +cd "$REPO_DIR" && stack build && stack install diff --git a/@ether/library/Language/Granule/repl.sh b/@ether/library/Language/Granule/repl.sh new file mode 100755 index 00000000..6e1ac919 --- /dev/null +++ b/@ether/library/Language/Granule/repl.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v grepl >/dev/null 2>&1; then + exec grepl +else + exec granule --repl +fi diff --git a/@ether/library/Language/Granule/run.sh b/@ether/library/Language/Granule/run.sh new file mode 100755 index 00000000..32783f34 --- /dev/null +++ b/@ether/library/Language/Granule/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v gr >/dev/null 2>&1; then + exec gr "$1" +else + exec granule "$1" +fi diff --git a/@ether/library/Language/GraphQL/check.sh b/@ether/library/Language/GraphQL/check.sh new file mode 100755 index 00000000..1fd5192b --- /dev/null +++ b/@ether/library/Language/GraphQL/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v graphql-lsp >/dev/null 2>&1 || command -v npx >/dev/null 2>&1 diff --git a/@ether/library/Language/GraphQL/install.sh b/@ether/library/Language/GraphQL/install.sh new file mode 100755 index 00000000..a4a229d7 --- /dev/null +++ b/@ether/library/Language/GraphQL/install.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +# GraphQL is a query language specification; no standalone runtime to install. +# Install graphql-js reference implementation for validation/execution. +if command -v npm >/dev/null 2>&1; then + npm install -g graphql graphql-language-service-cli +else + echo "npm is required to install GraphQL tooling. Install Node.js first." >&2 + exit 1 +fi diff --git a/@ether/library/Language/GraphQL/repl.sh b/@ether/library/Language/GraphQL/repl.sh new file mode 100755 index 00000000..e36527f5 --- /dev/null +++ b/@ether/library/Language/GraphQL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "GraphQL is a query specification and does not have a standalone REPL." >&2 +exit 1 diff --git a/@ether/library/Language/GraphQL/run.sh b/@ether/library/Language/GraphQL/run.sh new file mode 100755 index 00000000..1f7c816d --- /dev/null +++ b/@ether/library/Language/GraphQL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$1" diff --git a/@ether/library/Language/GraphViz/check.sh b/@ether/library/Language/GraphViz/check.sh new file mode 100755 index 00000000..db7d50be --- /dev/null +++ b/@ether/library/Language/GraphViz/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v dot >/dev/null 2>&1 diff --git a/@ether/library/Language/GraphViz/install.sh b/@ether/library/Language/GraphViz/install.sh new file mode 100755 index 00000000..cbf03ca4 --- /dev/null +++ b/@ether/library/Language/GraphViz/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing GraphViz from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/gitlab.com/graphviz/graphviz" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://gitlab.com/graphviz/graphviz.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cmake -B build -DCMAKE_INSTALL_PREFIX="$HOME/.local" && cmake --build build -j"$(nproc)" && cmake --install build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install graphviz +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y graphviz +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y graphviz +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm graphviz +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/GraphViz/repl.sh b/@ether/library/Language/GraphViz/repl.sh new file mode 100755 index 00000000..0682fc2a --- /dev/null +++ b/@ether/library/Language/GraphViz/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "GraphViz does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/GraphViz/run.sh b/@ether/library/Language/GraphViz/run.sh new file mode 100755 index 00000000..90b29c65 --- /dev/null +++ b/@ether/library/Language/GraphViz/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec dot -Tpng -O "$1" diff --git a/@ether/library/Language/Gravity/check.sh b/@ether/library/Language/Gravity/check.sh new file mode 100755 index 00000000..9f10ba25 --- /dev/null +++ b/@ether/library/Language/Gravity/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v gravity >/dev/null 2>&1 diff --git a/@ether/library/Language/Gravity/install.sh b/@ether/library/Language/Gravity/install.sh new file mode 100755 index 00000000..234f0598 --- /dev/null +++ b/@ether/library/Language/Gravity/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Gravity programming language +echo "Installing Gravity from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/marcobambini/gravity" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/marcobambini/gravity.git "$REPO_DIR" +fi +cd "$REPO_DIR" +mkdir -p build && cd build +cmake .. +make -j"$(nproc)" +sudo cp gravity /usr/local/bin/ diff --git a/@ether/library/Language/Gravity/packages.sh b/@ether/library/Language/Gravity/packages.sh new file mode 100755 index 00000000..0a25357f --- /dev/null +++ b/@ether/library/Language/Gravity/packages.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Gravity does not have a package manager." diff --git a/@ether/library/Language/Gravity/repl.sh b/@ether/library/Language/Gravity/repl.sh new file mode 100755 index 00000000..e7edd720 --- /dev/null +++ b/@ether/library/Language/Gravity/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Gravity does not have an interactive REPL. Run scripts with: gravity " diff --git a/@ether/library/Language/Gravity/run.sh b/@ether/library/Language/Gravity/run.sh new file mode 100755 index 00000000..e4f0cf74 --- /dev/null +++ b/@ether/library/Language/Gravity/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gravity "$@" diff --git a/@ether/library/Language/Grep/check.sh b/@ether/library/Language/Grep/check.sh new file mode 100755 index 00000000..383635bc --- /dev/null +++ b/@ether/library/Language/Grep/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v grep >/dev/null 2>&1 diff --git a/@ether/library/Language/Grep/install.sh b/@ether/library/Language/Grep/install.sh new file mode 100755 index 00000000..aaafe0f0 --- /dev/null +++ b/@ether/library/Language/Grep/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing GNU grep from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/gnu/grep" + mkdir -p "$REPO_DIR" + cd "$REPO_DIR" + curl -fsSL https://ftp.gnu.org/gnu/grep/grep-3.11.tar.xz -o grep.tar.xz + tar xf grep.tar.xz --strip-components=1 + ./configure --prefix="$HOME/.local" && make -j"$(nproc)" && make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install grep +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y grep +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y grep +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm grep +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Grep/repl.sh b/@ether/library/Language/Grep/repl.sh new file mode 100755 index 00000000..c758928f --- /dev/null +++ b/@ether/library/Language/Grep/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Grep does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Grep/run.sh b/@ether/library/Language/Grep/run.sh new file mode 100755 index 00000000..4419129e --- /dev/null +++ b/@ether/library/Language/Grep/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec grep -f "$1" diff --git a/@ether/library/Language/Groovy/check.sh b/@ether/library/Language/Groovy/check.sh new file mode 100755 index 00000000..59bc4ea1 --- /dev/null +++ b/@ether/library/Language/Groovy/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v groovy >/dev/null 2>&1 diff --git a/@ether/library/Language/Groovy/install.sh b/@ether/library/Language/Groovy/install.sh new file mode 100755 index 00000000..eaa6f190 --- /dev/null +++ b/@ether/library/Language/Groovy/install.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Groovy from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/apache/groovy" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/apache/groovy.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./gradlew installGroovy + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install groovy +elif command -v sdk >/dev/null 2>&1; then + sdk install groovy +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y groovy +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y groovy +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm groovy +else + # Install via SDKMAN (official recommendation) + curl -s "https://get.sdkman.io" | bash + source "$HOME/.sdkman/bin/sdkman-init.sh" + sdk install groovy +fi diff --git a/@ether/library/Language/Groovy/repl.sh b/@ether/library/Language/Groovy/repl.sh new file mode 100755 index 00000000..45f9e703 --- /dev/null +++ b/@ether/library/Language/Groovy/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec groovysh diff --git a/@ether/library/Language/Groovy/run.sh b/@ether/library/Language/Groovy/run.sh new file mode 100755 index 00000000..41d57022 --- /dev/null +++ b/@ether/library/Language/Groovy/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec groovy "$1" diff --git a/@ether/library/Language/Guile/check.sh b/@ether/library/Language/Guile/check.sh new file mode 100755 index 00000000..771cbce5 --- /dev/null +++ b/@ether/library/Language/Guile/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v guile >/dev/null 2>&1 diff --git a/@ether/library/Language/Guile/install.sh b/@ether/library/Language/Guile/install.sh new file mode 100755 index 00000000..8f9cb3e5 --- /dev/null +++ b/@ether/library/Language/Guile/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing GNU Guile from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/gnu/guile" + mkdir -p "$REPO_DIR" + cd "$REPO_DIR" + curl -fsSL https://ftp.gnu.org/gnu/guile/guile-3.0.10.tar.xz -o guile.tar.xz + tar xf guile.tar.xz --strip-components=1 + ./configure --prefix="$HOME/.local" && make -j"$(nproc)" && make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install guile +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y guile-3.0 +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y guile30 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm guile +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Guile/repl.sh b/@ether/library/Language/Guile/repl.sh new file mode 100755 index 00000000..28461b2b --- /dev/null +++ b/@ether/library/Language/Guile/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec guile diff --git a/@ether/library/Language/Guile/run.sh b/@ether/library/Language/Guile/run.sh new file mode 100755 index 00000000..a7319cc9 --- /dev/null +++ b/@ether/library/Language/Guile/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec guile -s "$1" diff --git a/@ether/library/Language/Guppy/check.sh b/@ether/library/Language/Guppy/check.sh new file mode 100755 index 00000000..116274bd --- /dev/null +++ b/@ether/library/Language/Guppy/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import guppylang" >/dev/null 2>&1 diff --git a/@ether/library/Language/Guppy/install.sh b/@ether/library/Language/Guppy/install.sh new file mode 100755 index 00000000..a160b1cb --- /dev/null +++ b/@ether/library/Language/Guppy/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Guppy from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/CQCL/guppylang" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/CQCL/guppylang.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install guppylang diff --git a/@ether/library/Language/Guppy/repl.sh b/@ether/library/Language/Guppy/repl.sh new file mode 100755 index 00000000..6a96594a --- /dev/null +++ b/@ether/library/Language/Guppy/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import guppylang; import code; code.interact(local={'guppylang': guppylang})" diff --git a/@ether/library/Language/Guppy/run.sh b/@ether/library/Language/Guppy/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/Guppy/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Guru/check.sh b/@ether/library/Language/Guru/check.sh new file mode 100755 index 00000000..384e616d --- /dev/null +++ b/@ether/library/Language/Guru/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v guru >/dev/null 2>&1 diff --git a/@ether/library/Language/Guru/install.sh b/@ether/library/Language/Guru/install.sh new file mode 100755 index 00000000..e6bd1f14 --- /dev/null +++ b/@ether/library/Language/Guru/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# Guru is an academic dependently-typed language described in: +# https://dl.acm.org/doi/10.1145/1481848.1481856 +# No public package or binary distribution is available. +echo "Guru is an academic language without a public distribution." >&2 +echo "See: https://dl.acm.org/doi/10.1145/1481848.1481856" >&2 +exit 1 diff --git a/@ether/library/Language/Guru/repl.sh b/@ether/library/Language/Guru/repl.sh new file mode 100755 index 00000000..5438fc79 --- /dev/null +++ b/@ether/library/Language/Guru/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Guru does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Guru/run.sh b/@ether/library/Language/Guru/run.sh new file mode 100755 index 00000000..b9b35356 --- /dev/null +++ b/@ether/library/Language/Guru/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Guru has no public runtime available." >&2 +exit 1 diff --git a/@ether/library/Language/HLSL/check.sh b/@ether/library/Language/HLSL/check.sh new file mode 100755 index 00000000..7f170e43 --- /dev/null +++ b/@ether/library/Language/HLSL/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v dxc >/dev/null 2>&1 diff --git a/@ether/library/Language/HLSL/install.sh b/@ether/library/Language/HLSL/install.sh new file mode 100755 index 00000000..5f040629 --- /dev/null +++ b/@ether/library/Language/HLSL/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing DirectX Shader Compiler from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/microsoft/DirectXShaderCompiler" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/microsoft/DirectXShaderCompiler.git "$REPO_DIR" --recurse-submodules + fi + cd "$REPO_DIR" && cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$HOME/.local" && cmake --build build -j"$(nproc)" && cmake --install build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install dxc +elif command -v apt-get >/dev/null 2>&1; then + # Install prebuilt from GitHub releases + ARCH=$(uname -m) + VERSION=$(curl -sSL https://api.github.com/repos/microsoft/DirectXShaderCompiler/releases/latest | grep '"tag_name"' | sed 's/.*"\(.*\)".*/\1/') + curl -fsSL "https://github.com/microsoft/DirectXShaderCompiler/releases/download/${VERSION}/linux_dxc_${VERSION#v}.x86_64.tar.gz" -o /tmp/dxc.tar.gz + sudo mkdir -p /usr/local/dxc && sudo tar -xzf /tmp/dxc.tar.gz -C /usr/local/dxc + sudo ln -sf /usr/local/dxc/bin/dxc /usr/local/bin/dxc + rm -f /tmp/dxc.tar.gz +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm directx-shader-compiler +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/HLSL/repl.sh b/@ether/library/Language/HLSL/repl.sh new file mode 100755 index 00000000..5c0844de --- /dev/null +++ b/@ether/library/Language/HLSL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "HLSL is a shader language and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/HLSL/run.sh b/@ether/library/Language/HLSL/run.sh new file mode 100755 index 00000000..cc7bab4a --- /dev/null +++ b/@ether/library/Language/HLSL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec dxc "$1" diff --git a/@ether/library/Language/HOL/check.sh b/@ether/library/Language/HOL/check.sh new file mode 100755 index 00000000..c5cb19dd --- /dev/null +++ b/@ether/library/Language/HOL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/HOL-Theorem-Prover/HOL" +command -v hol >/dev/null 2>&1 || [[ -x "$REPO_DIR/bin/hol" ]] diff --git a/@ether/library/Language/HOL/install.sh b/@ether/library/Language/HOL/install.sh new file mode 100755 index 00000000..da701e04 --- /dev/null +++ b/@ether/library/Language/HOL/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing HOL from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/HOL-Theorem-Prover/HOL" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/HOL-Theorem-Prover/HOL.git "$REPO_DIR" +fi +cd "$REPO_DIR" && poly < tools/smart-configure.sml && bin/build diff --git a/@ether/library/Language/HOL/repl.sh b/@ether/library/Language/HOL/repl.sh new file mode 100755 index 00000000..59ca6c57 --- /dev/null +++ b/@ether/library/Language/HOL/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/HOL-Theorem-Prover/HOL" +if command -v hol >/dev/null 2>&1; then + exec hol +else + exec "$REPO_DIR/bin/hol" +fi diff --git a/@ether/library/Language/HOL/run.sh b/@ether/library/Language/HOL/run.sh new file mode 100755 index 00000000..07affbfd --- /dev/null +++ b/@ether/library/Language/HOL/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/HOL-Theorem-Prover/HOL" +if command -v hol >/dev/null 2>&1; then + exec hol < "$1" +else + exec "$REPO_DIR/bin/hol" < "$1" +fi diff --git a/@ether/library/Language/HQ9/check.sh b/@ether/library/Language/HQ9/check.sh new file mode 100755 index 00000000..72655102 --- /dev/null +++ b/@ether/library/Language/HQ9/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v hq9plus >/dev/null 2>&1 || [[ -x "$HOME/.local/bin/hq9plus" ]] diff --git a/@ether/library/Language/HQ9/install.sh b/@ether/library/Language/HQ9/install.sh new file mode 100755 index 00000000..6ede0a90 --- /dev/null +++ b/@ether/library/Language/HQ9/install.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +# HQ9+ is a trivial esoteric language. We provide a minimal interpreter. +# See: https://esolangs.org/wiki/HQ9%2B +HQ9_BIN="$HOME/.local/bin/hq9plus" +mkdir -p "$HOME/.local/bin" +cat > "$HQ9_BIN" << 'INTERP' +#!/usr/bin/env python3 +import sys +if len(sys.argv) < 2: + print("Usage: hq9plus ", file=sys.stderr); sys.exit(1) +with open(sys.argv[1]) as f: + code = f.read() +acc = 0 +for c in code: + if c == 'H': + print("Hello, World!") + elif c == 'Q': + print(code, end='') + elif c == '9': + for i in range(99, 0, -1): + b = "bottle" if i == 1 else "bottles" + b2 = "bottle" if i - 1 == 1 else "bottles" + print(f"{i} {b} of beer on the wall, {i} {b} of beer.") + if i > 1: + print(f"Take one down and pass it around, {i-1} {b2} of beer on the wall.\n") + else: + print("Go to the store and buy some more, 99 bottles of beer on the wall.\n") + elif c == '+': + acc += 1 +INTERP +chmod +x "$HQ9_BIN" +echo "HQ9+ interpreter installed to $HQ9_BIN" diff --git a/@ether/library/Language/HQ9/repl.sh b/@ether/library/Language/HQ9/repl.sh new file mode 100755 index 00000000..5fa9bcb0 --- /dev/null +++ b/@ether/library/Language/HQ9/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "HQ9+ does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/HQ9/run.sh b/@ether/library/Language/HQ9/run.sh new file mode 100755 index 00000000..5062d062 --- /dev/null +++ b/@ether/library/Language/HQ9/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v hq9plus >/dev/null 2>&1; then + exec hq9plus "$1" +else + exec "$HOME/.local/bin/hq9plus" "$1" +fi diff --git a/@ether/library/Language/HTML/check.sh b/@ether/library/Language/HTML/check.sh new file mode 100755 index 00000000..3d34fe33 --- /dev/null +++ b/@ether/library/Language/HTML/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# HTML is a markup language; always available. +exit 0 diff --git a/@ether/library/Language/HTML/install.sh b/@ether/library/Language/HTML/install.sh new file mode 100755 index 00000000..b3bca133 --- /dev/null +++ b/@ether/library/Language/HTML/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# HTML is a markup language; no installation required. +echo "HTML requires no installation. Use a web browser to view HTML files." diff --git a/@ether/library/Language/HTML/repl.sh b/@ether/library/Language/HTML/repl.sh new file mode 100755 index 00000000..957ce4cb --- /dev/null +++ b/@ether/library/Language/HTML/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "HTML is a markup language and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/HTML/run.sh b/@ether/library/Language/HTML/run.sh new file mode 100755 index 00000000..1f7c816d --- /dev/null +++ b/@ether/library/Language/HTML/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$1" diff --git a/@ether/library/Language/HVM/check.sh b/@ether/library/Language/HVM/check.sh new file mode 100755 index 00000000..cf348adc --- /dev/null +++ b/@ether/library/Language/HVM/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v hvm >/dev/null 2>&1 diff --git a/@ether/library/Language/HVM/install.sh b/@ether/library/Language/HVM/install.sh new file mode 100755 index 00000000..85a3dc96 --- /dev/null +++ b/@ether/library/Language/HVM/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing HVM from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/HigherOrderCO/HVM" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/HigherOrderCO/HVM.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release && cp target/release/hvm "$HOME/.local/bin/" + exit 0 +fi +# Official install via cargo (https://github.com/HigherOrderCO/HVM) +cargo install hvm diff --git a/@ether/library/Language/HVM/repl.sh b/@ether/library/Language/HVM/repl.sh new file mode 100755 index 00000000..b0f79ba5 --- /dev/null +++ b/@ether/library/Language/HVM/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "HVM does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/HVM/run.sh b/@ether/library/Language/HVM/run.sh new file mode 100755 index 00000000..edb338e2 --- /dev/null +++ b/@ether/library/Language/HVM/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec hvm run "$1" diff --git a/@ether/library/Language/Hack/check.sh b/@ether/library/Language/Hack/check.sh new file mode 100755 index 00000000..45f85919 --- /dev/null +++ b/@ether/library/Language/Hack/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v hhvm >/dev/null 2>&1 diff --git a/@ether/library/Language/Hack/install.sh b/@ether/library/Language/Hack/install.sh new file mode 100755 index 00000000..71cad7b4 --- /dev/null +++ b/@ether/library/Language/Hack/install.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing HHVM (Hack) from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/facebook/hhvm" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/facebook/hhvm.git "$REPO_DIR" --recurse-submodules + fi + cd "$REPO_DIR" && cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j"$(nproc)" + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew tap hhvm/hhvm && brew install hhvm +elif command -v apt-get >/dev/null 2>&1; then + # Official HHVM installation for Ubuntu/Debian (https://docs.hhvm.com/hhvm/installation/linux) + sudo apt-get update && sudo apt-get install -y software-properties-common apt-transport-https + sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xB4112585D386EB94 + DISTRO=$(lsb_release -sc) + sudo add-apt-repository "deb https://dl.hhvm.com/ubuntu ${DISTRO} main" + sudo apt-get update && sudo apt-get install -y hhvm +elif command -v dnf >/dev/null 2>&1; then + echo "HHVM does not officially support Fedora. Use --from-source." >&2; exit 1 +elif command -v pacman >/dev/null 2>&1; then + echo "HHVM does not officially support Arch. Use --from-source." >&2; exit 1 +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Hack/repl.sh b/@ether/library/Language/Hack/repl.sh new file mode 100755 index 00000000..eaba9adf --- /dev/null +++ b/@ether/library/Language/Hack/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Hack/HHVM does not have a built-in REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Hack/run.sh b/@ether/library/Language/Hack/run.sh new file mode 100755 index 00000000..9ed0a5b0 --- /dev/null +++ b/@ether/library/Language/Hack/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec hhvm "$1" diff --git a/@ether/library/Language/Hakaru/check.sh b/@ether/library/Language/Hakaru/check.sh new file mode 100755 index 00000000..4a6ae4fb --- /dev/null +++ b/@ether/library/Language/Hakaru/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v hakaru >/dev/null 2>&1 diff --git a/@ether/library/Language/Hakaru/install.sh b/@ether/library/Language/Hakaru/install.sh new file mode 100755 index 00000000..295d58b9 --- /dev/null +++ b/@ether/library/Language/Hakaru/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Hakaru from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hakaru-dev/hakaru" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/hakaru-dev/hakaru.git "$REPO_DIR" +fi +cd "$REPO_DIR" && stack build && stack install diff --git a/@ether/library/Language/Hakaru/repl.sh b/@ether/library/Language/Hakaru/repl.sh new file mode 100755 index 00000000..8deb62ca --- /dev/null +++ b/@ether/library/Language/Hakaru/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Hakaru does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Hakaru/run.sh b/@ether/library/Language/Hakaru/run.sh new file mode 100755 index 00000000..a8f9d4dd --- /dev/null +++ b/@ether/library/Language/Hakaru/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec hakaru "$1" diff --git a/@ether/library/Language/Halide/check.sh b/@ether/library/Language/Halide/check.sh new file mode 100755 index 00000000..8e77f655 --- /dev/null +++ b/@ether/library/Language/Halide/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Halide is a C++ library; check if the header exists +[[ -f /usr/include/Halide.h ]] || [[ -f /usr/local/include/Halide.h ]] || [[ -f "$HOME/.local/include/Halide.h" ]] diff --git a/@ether/library/Language/Halide/install.sh b/@ether/library/Language/Halide/install.sh new file mode 100755 index 00000000..cf9c1300 --- /dev/null +++ b/@ether/library/Language/Halide/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Halide from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/halide/Halide" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/halide/Halide.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$HOME/.local" && cmake --build build -j"$(nproc)" && cmake --install build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install halide +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y libhalide-dev +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm halide +else + echo "Install from source or use prebuilt release from GitHub." >&2 + echo "See: https://github.com/halide/Halide/releases" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Halide/repl.sh b/@ether/library/Language/Halide/repl.sh new file mode 100755 index 00000000..19682d46 --- /dev/null +++ b/@ether/library/Language/Halide/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Halide is a C++ DSL and does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Halide/run.sh b/@ether/library/Language/Halide/run.sh new file mode 100755 index 00000000..0dd4be1f --- /dev/null +++ b/@ether/library/Language/Halide/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +out="/tmp/halide_out" +g++ "$file" -lHalide -lpthread -ldl -o "$out" && "$out" diff --git a/@ether/library/Language/Haskell/check.sh b/@ether/library/Language/Haskell/check.sh new file mode 100755 index 00000000..3cbeb4a6 --- /dev/null +++ b/@ether/library/Language/Haskell/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v ghc >/dev/null 2>&1 diff --git a/@ether/library/Language/Haskell/install.sh b/@ether/library/Language/Haskell/install.sh new file mode 100755 index 00000000..35515721 --- /dev/null +++ b/@ether/library/Language/Haskell/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ghc/ghc" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ghc/ghc.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./boot && ./configure && make && make install + exit 0 +fi +curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh diff --git a/@ether/library/Language/Haskell/packages.sh b/@ether/library/Language/Haskell/packages.sh new file mode 100755 index 00000000..1db28e04 --- /dev/null +++ b/@ether/library/Language/Haskell/packages.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Haskell" +REGISTRIES=( + "Hackage: https://hackage.haskell.org" + "Stackage: https://www.stackage.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v cabal &>/dev/null; then + cabal list "$@" + else + echo "Visit: https://hackage.haskell.org/packages/search?terms=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v cabal &>/dev/null; then + cabal info "$1" + else + echo "Visit: https://hackage.haskell.org/package/$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + cabal install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Haskell/repl.sh b/@ether/library/Language/Haskell/repl.sh new file mode 100755 index 00000000..eb752604 --- /dev/null +++ b/@ether/library/Language/Haskell/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec ghci diff --git a/@ether/library/Language/Haskell/run.sh b/@ether/library/Language/Haskell/run.sh new file mode 100755 index 00000000..c03254e9 --- /dev/null +++ b/@ether/library/Language/Haskell/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +if [[ -d "$file" ]]; then + cd "$file" && cabal run 2>/dev/null || stack run +else + runghc "$file" +fi diff --git a/@ether/library/Language/Haxe/check.sh b/@ether/library/Language/Haxe/check.sh new file mode 100755 index 00000000..2b3a8b74 --- /dev/null +++ b/@ether/library/Language/Haxe/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v haxe >/dev/null 2>&1 diff --git a/@ether/library/Language/Haxe/install.sh b/@ether/library/Language/Haxe/install.sh new file mode 100755 index 00000000..96ef9be1 --- /dev/null +++ b/@ether/library/Language/Haxe/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Haxe +if [[ "$(uname)" == "Darwin" ]]; then + brew install haxe +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y haxe +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y haxe +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm haxe +else + echo "Unsupported package manager. Download from https://haxe.org/download/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Haxe/packages.sh b/@ether/library/Language/Haxe/packages.sh new file mode 100755 index 00000000..9b4b57f6 --- /dev/null +++ b/@ether/library/Language/Haxe/packages.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://lib.haxe.org" + +usage() { + echo "Haxe Package Manager (haxelib)" + echo "" + echo "Registry: $REGISTRY" + echo "" + echo "Usage: packages.sh [args]" + echo "" + echo "Commands:" + echo " search Search for libraries" + echo " info Show library information" + echo " install Install a library" +} + +cmd_search() { + if command -v haxelib &>/dev/null; then + haxelib search "$@" + else + echo "haxelib not found. Search online:" + echo " $REGISTRY" + fi +} + +cmd_info() { + local lib="$1" + if command -v haxelib &>/dev/null; then + haxelib info "$lib" + else + echo "haxelib not found. View online:" + echo " $REGISTRY/p/$lib" + fi +} + +cmd_install() { + local lib="$1" + if command -v haxelib &>/dev/null; then + haxelib install "$lib" + else + echo "haxelib not found. Install Haxe first:" + echo " https://haxe.org/download/" + fi +} + +case "${1:-}" in + search) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh search "; exit 1; } + cmd_search "$@" + ;; + info) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh info "; exit 1; } + cmd_info "$1" + ;; + install) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh install "; exit 1; } + cmd_install "$1" + ;; + *) + usage + ;; +esac diff --git a/@ether/library/Language/Haxe/repl.sh b/@ether/library/Language/Haxe/repl.sh new file mode 100755 index 00000000..150f5988 --- /dev/null +++ b/@ether/library/Language/Haxe/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Haxe does not have a standard REPL. Try the online evaluator: https://try.haxe.org/" diff --git a/@ether/library/Language/Haxe/run.sh b/@ether/library/Language/Haxe/run.sh new file mode 100755 index 00000000..c9358c73 --- /dev/null +++ b/@ether/library/Language/Haxe/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec haxe "$@" diff --git a/@ether/library/Language/Helios/check.sh b/@ether/library/Language/Helios/check.sh new file mode 100755 index 00000000..4c6ffe47 --- /dev/null +++ b/@ether/library/Language/Helios/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v helios >/dev/null 2>&1 || npm list -g @hyperionbt/helios >/dev/null 2>&1 diff --git a/@ether/library/Language/Helios/install.sh b/@ether/library/Language/Helios/install.sh new file mode 100755 index 00000000..2604b36f --- /dev/null +++ b/@ether/library/Language/Helios/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Helios: Cardano smart contract language - https://www.hyperion-bt.org/helios-book +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hyperion-bt/helios" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/hyperion-bt/helios.git "$REPO_DIR" + fi + cd "$REPO_DIR" && npm install && npm run build + exit 0 +fi +npm install -g @hyperionbt/helios diff --git a/@ether/library/Language/Helios/packages.sh b/@ether/library/Language/Helios/packages.sh new file mode 100755 index 00000000..f8fc434c --- /dev/null +++ b/@ether/library/Language/Helios/packages.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Helios" +REGISTRIES=( + "npm: https://www.npmjs.com" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Note: Helios uses the npm ecosystem." + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v npm &>/dev/null; then + npm search helios-"$@" + else + echo "Visit: https://www.npmjs.com/search?q=helios-$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v npm &>/dev/null; then + npm info "$1" + else + echo "Visit: https://www.npmjs.com/package/$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + npm install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Helios/repl.sh b/@ether/library/Language/Helios/repl.sh new file mode 100755 index 00000000..b936e571 --- /dev/null +++ b/@ether/library/Language/Helios/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Helios does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Helios/run.sh b/@ether/library/Language/Helios/run.sh new file mode 100755 index 00000000..b04e4206 --- /dev/null +++ b/@ether/library/Language/Helios/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec helios "$@" diff --git a/@ether/library/Language/Hoon/check.sh b/@ether/library/Language/Hoon/check.sh new file mode 100755 index 00000000..167fb1c9 --- /dev/null +++ b/@ether/library/Language/Hoon/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v urbit >/dev/null 2>&1 diff --git a/@ether/library/Language/Hoon/install.sh b/@ether/library/Language/Hoon/install.sh new file mode 100755 index 00000000..18af15da --- /dev/null +++ b/@ether/library/Language/Hoon/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# Hoon - Urbit's programming language +if [[ "$(uname)" == "Darwin" ]]; then + brew install urbit +elif command -v apt-get >/dev/null 2>&1; then + echo "Download Urbit runtime from https://urbit.org/getting-started" >&2 + echo "Linux install: curl -L https://urbit.org/install/linux-x86_64/latest | tar xzk --transform='s/.*/urbit/g'" >&2 + exit 1 +else + echo "Download Urbit runtime from https://urbit.org/getting-started" >&2; exit 1 +fi diff --git a/@ether/library/Language/Hoon/packages.sh b/@ether/library/Language/Hoon/packages.sh new file mode 100755 index 00000000..a083a05f --- /dev/null +++ b/@ether/library/Language/Hoon/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Hoon does not have a standard package manager." +echo "Urbit desks serve as the distribution mechanism." diff --git a/@ether/library/Language/Hoon/repl.sh b/@ether/library/Language/Hoon/repl.sh new file mode 100755 index 00000000..7b533245 --- /dev/null +++ b/@ether/library/Language/Hoon/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Start an Urbit ship to use the Hoon REPL (dojo): urbit " diff --git a/@ether/library/Language/Hoon/run.sh b/@ether/library/Language/Hoon/run.sh new file mode 100755 index 00000000..1ee34d7b --- /dev/null +++ b/@ether/library/Language/Hoon/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Hoon runs within the Urbit runtime. Start a ship with: urbit " diff --git a/@ether/library/Language/Hy/check.sh b/@ether/library/Language/Hy/check.sh new file mode 100755 index 00000000..d8028cb9 --- /dev/null +++ b/@ether/library/Language/Hy/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v hy >/dev/null 2>&1 diff --git a/@ether/library/Language/Hy/install.sh b/@ether/library/Language/Hy/install.sh new file mode 100755 index 00000000..a552c491 --- /dev/null +++ b/@ether/library/Language/Hy/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Hy from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hylang/hy" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/hylang/hy.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install hy diff --git a/@ether/library/Language/Hy/repl.sh b/@ether/library/Language/Hy/repl.sh new file mode 100755 index 00000000..85d6b70a --- /dev/null +++ b/@ether/library/Language/Hy/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec hy diff --git a/@ether/library/Language/Hy/run.sh b/@ether/library/Language/Hy/run.sh new file mode 100755 index 00000000..13b333ac --- /dev/null +++ b/@ether/library/Language/Hy/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec hy "$1" diff --git a/@ether/library/Language/Hylo/check.sh b/@ether/library/Language/Hylo/check.sh new file mode 100755 index 00000000..50cea52e --- /dev/null +++ b/@ether/library/Language/Hylo/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hylo-lang/hylo" +command -v hylo >/dev/null 2>&1 || [[ -x "$REPO_DIR/.build/release/hc" ]] diff --git a/@ether/library/Language/Hylo/install.sh b/@ether/library/Language/Hylo/install.sh new file mode 100755 index 00000000..cd889f37 --- /dev/null +++ b/@ether/library/Language/Hylo/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Hylo from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hylo-lang/hylo" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/hylo-lang/hylo.git "$REPO_DIR" +fi +cd "$REPO_DIR" && swift build -c release +echo "Hylo built. Binary at $REPO_DIR/.build/release/" diff --git a/@ether/library/Language/Hylo/repl.sh b/@ether/library/Language/Hylo/repl.sh new file mode 100755 index 00000000..cf62e010 --- /dev/null +++ b/@ether/library/Language/Hylo/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Hylo does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Hylo/run.sh b/@ether/library/Language/Hylo/run.sh new file mode 100755 index 00000000..35363196 --- /dev/null +++ b/@ether/library/Language/Hylo/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hylo-lang/hylo" +if command -v hc >/dev/null 2>&1; then + exec hc "$1" +else + exec "$REPO_DIR/.build/release/hc" "$1" +fi diff --git a/@ether/library/Language/IBAL/check.sh b/@ether/library/Language/IBAL/check.sh new file mode 100755 index 00000000..a26b9a62 --- /dev/null +++ b/@ether/library/Language/IBAL/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v ibal >/dev/null 2>&1 diff --git a/@ether/library/Language/IBAL/install.sh b/@ether/library/Language/IBAL/install.sh new file mode 100755 index 00000000..766e0557 --- /dev/null +++ b/@ether/library/Language/IBAL/install.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +# IBAL is an academic probabilistic rational programming language. +# No public distribution is available. +echo "IBAL is an academic language without a public distribution." >&2 +echo "See: https://www.researchgate.net/publication/2366378_IBAL_A_Probabilistic_Rational_Programming_Language" >&2 +exit 1 diff --git a/@ether/library/Language/IBAL/repl.sh b/@ether/library/Language/IBAL/repl.sh new file mode 100755 index 00000000..526776e1 --- /dev/null +++ b/@ether/library/Language/IBAL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "IBAL does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/IBAL/run.sh b/@ether/library/Language/IBAL/run.sh new file mode 100755 index 00000000..b0cab818 --- /dev/null +++ b/@ether/library/Language/IBAL/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "IBAL has no public runtime available." >&2 +exit 1 diff --git a/@ether/library/Language/INI/check.sh b/@ether/library/Language/INI/check.sh new file mode 100755 index 00000000..87b20e80 --- /dev/null +++ b/@ether/library/Language/INI/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# INI is a data format; always available. +exit 0 diff --git a/@ether/library/Language/INI/install.sh b/@ether/library/Language/INI/install.sh new file mode 100755 index 00000000..57fde4be --- /dev/null +++ b/@ether/library/Language/INI/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# INI is a configuration file format. No installation required. +echo "INI is a data format. No installation required." diff --git a/@ether/library/Language/INI/repl.sh b/@ether/library/Language/INI/repl.sh new file mode 100755 index 00000000..d0b77a88 --- /dev/null +++ b/@ether/library/Language/INI/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "INI is a data format and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/INI/run.sh b/@ether/library/Language/INI/run.sh new file mode 100755 index 00000000..1f7c816d --- /dev/null +++ b/@ether/library/Language/INI/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$1" diff --git a/@ether/library/Language/Icon/check.sh b/@ether/library/Language/Icon/check.sh new file mode 100755 index 00000000..20f016ac --- /dev/null +++ b/@ether/library/Language/Icon/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v icont >/dev/null 2>&1 diff --git a/@ether/library/Language/Icon/install.sh b/@ether/library/Language/Icon/install.sh new file mode 100755 index 00000000..9df5fbfe --- /dev/null +++ b/@ether/library/Language/Icon/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +# Icon programming language +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Icon from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/icon-src" + mkdir -p "$REPO_DIR" && cd "$REPO_DIR" + curl -LO https://www.cs.arizona.edu/icon/ftp/packages/unix/icon-v951src.tgz + tar xzf icon-v951src.tgz + cd icon-v951src + make Configure name=linux + make + sudo make Install dest=/usr/local + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + echo "Icon is not in Homebrew. Use --from-source or visit https://www.cs.arizona.edu/icon/" >&2; exit 1 +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y icon +elif command -v pacman >/dev/null 2>&1; then + echo "Check AUR for icon: yay -S icon" >&2; exit 1 +else + echo "Unsupported package manager. Use --from-source or visit https://www.cs.arizona.edu/icon/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Icon/packages.sh b/@ether/library/Language/Icon/packages.sh new file mode 100755 index 00000000..b26e8721 --- /dev/null +++ b/@ether/library/Language/Icon/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Icon does not have a package manager." +echo "Icon Program Library: https://www.cs.arizona.edu/icon/library/" diff --git a/@ether/library/Language/Icon/repl.sh b/@ether/library/Language/Icon/repl.sh new file mode 100755 index 00000000..852926ab --- /dev/null +++ b/@ether/library/Language/Icon/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Icon does not have an interactive REPL." diff --git a/@ether/library/Language/Icon/run.sh b/@ether/library/Language/Icon/run.sh new file mode 100755 index 00000000..5ca448be --- /dev/null +++ b/@ether/library/Language/Icon/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +icont -s "$1" -x diff --git a/@ether/library/Language/Idris/check.sh b/@ether/library/Language/Idris/check.sh new file mode 100755 index 00000000..35c52851 --- /dev/null +++ b/@ether/library/Language/Idris/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v idris2 >/dev/null 2>&1 diff --git a/@ether/library/Language/Idris/install.sh b/@ether/library/Language/Idris/install.sh new file mode 100755 index 00000000..d4f9b83d --- /dev/null +++ b/@ether/library/Language/Idris/install.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/idris-lang/Idris2" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/idris-lang/Idris2.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make bootstrap && make install + exit 0 +fi +if command -v pack >/dev/null 2>&1; then + pack install idris2 +elif [[ "$(uname)" == "Darwin" ]]; then + brew install idris2 +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y idris2 2>/dev/null || { echo "Build from source: ether Language.Idris install --from-source" >&2; exit 1; } +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Idris/repl.sh b/@ether/library/Language/Idris/repl.sh new file mode 100755 index 00000000..59b84cd0 --- /dev/null +++ b/@ether/library/Language/Idris/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec idris2 diff --git a/@ether/library/Language/Idris/run.sh b/@ether/library/Language/Idris/run.sh new file mode 100755 index 00000000..d51d648c --- /dev/null +++ b/@ether/library/Language/Idris/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec idris2 "$@" diff --git a/@ether/library/Language/Imandra/check.sh b/@ether/library/Language/Imandra/check.sh new file mode 100755 index 00000000..f5e4f26a --- /dev/null +++ b/@ether/library/Language/Imandra/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v imandra >/dev/null 2>&1 diff --git a/@ether/library/Language/Imandra/install.sh b/@ether/library/Language/Imandra/install.sh new file mode 100755 index 00000000..61aac6f5 --- /dev/null +++ b/@ether/library/Language/Imandra/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official installation via the Imandra installer (https://docs.imandra.ai/imandra-docs/notebooks/installation/) +if [[ "$(uname)" == "Darwin" ]] || [[ "$(uname)" == "Linux" ]]; then + bash <(curl -s "https://storage.googleapis.com/imandra-do/install.sh") +else + echo "Unsupported platform. See https://www.imandra.ai/ for installation." >&2 + exit 1 +fi diff --git a/@ether/library/Language/Imandra/repl.sh b/@ether/library/Language/Imandra/repl.sh new file mode 100755 index 00000000..2d307dfa --- /dev/null +++ b/@ether/library/Language/Imandra/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec imandra diff --git a/@ether/library/Language/Imandra/run.sh b/@ether/library/Language/Imandra/run.sh new file mode 100755 index 00000000..b49797a4 --- /dev/null +++ b/@ether/library/Language/Imandra/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec imandra "$1" diff --git a/@ether/library/Language/Infer.NET/check.sh b/@ether/library/Language/Infer.NET/check.sh new file mode 100755 index 00000000..b4cea5bf --- /dev/null +++ b/@ether/library/Language/Infer.NET/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v dotnet >/dev/null 2>&1 diff --git a/@ether/library/Language/Infer.NET/install.sh b/@ether/library/Language/Infer.NET/install.sh new file mode 100755 index 00000000..94b15b6e --- /dev/null +++ b/@ether/library/Language/Infer.NET/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Infer.NET from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/dotnet/infer" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/dotnet/infer.git "$REPO_DIR" + fi + cd "$REPO_DIR" && dotnet build -c Release + exit 0 +fi +# Infer.NET is a .NET library; install via NuGet/dotnet +command -v dotnet >/dev/null 2>&1 || { echo ".NET SDK is required. Install it first." >&2; exit 1; } +echo "Add Infer.NET to your project: dotnet add package Microsoft.ML.Probabilistic" +dotnet new console -o /tmp/infernet-check 2>/dev/null || true +cd /tmp/infernet-check && dotnet add package Microsoft.ML.Probabilistic && dotnet add package Microsoft.ML.Probabilistic.Compiler diff --git a/@ether/library/Language/Infer.NET/repl.sh b/@ether/library/Language/Infer.NET/repl.sh new file mode 100755 index 00000000..c65e364b --- /dev/null +++ b/@ether/library/Language/Infer.NET/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec dotnet csharp diff --git a/@ether/library/Language/Infer.NET/run.sh b/@ether/library/Language/Infer.NET/run.sh new file mode 100755 index 00000000..5367654b --- /dev/null +++ b/@ether/library/Language/Infer.NET/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec dotnet run --project "$1" diff --git a/@ether/library/Language/Inform7/check.sh b/@ether/library/Language/Inform7/check.sh new file mode 100755 index 00000000..fc34556b --- /dev/null +++ b/@ether/library/Language/Inform7/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v inform7 >/dev/null 2>&1 || command -v ni >/dev/null 2>&1 diff --git a/@ether/library/Language/Inform7/install.sh b/@ether/library/Language/Inform7/install.sh new file mode 100755 index 00000000..2cd8b1a1 --- /dev/null +++ b/@ether/library/Language/Inform7/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Inform 7 - interactive fiction language +if [[ "$(uname)" == "Darwin" ]]; then + echo "Download Inform 7 from https://ganelson.github.io/inform-website/" >&2 + echo "macOS app available at: https://ganelson.github.io/inform-website/downloads.html" >&2 + exit 1 +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y inform7 || { + echo "inform7 not in repos. Download from https://ganelson.github.io/inform-website/" >&2; exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + echo "Check AUR for inform7: yay -S inform7" >&2; exit 1 +else + echo "Download Inform 7 from https://ganelson.github.io/inform-website/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Inform7/packages.sh b/@ether/library/Language/Inform7/packages.sh new file mode 100755 index 00000000..31bc9027 --- /dev/null +++ b/@ether/library/Language/Inform7/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Inform 7 does not have a package manager." +echo "Extensions: https://github.com/ganelson/inform-public-library" diff --git a/@ether/library/Language/Inform7/repl.sh b/@ether/library/Language/Inform7/repl.sh new file mode 100755 index 00000000..e73ca84d --- /dev/null +++ b/@ether/library/Language/Inform7/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Inform 7 does not have an interactive REPL." diff --git a/@ether/library/Language/Inform7/run.sh b/@ether/library/Language/Inform7/run.sh new file mode 100755 index 00000000..0af4905f --- /dev/null +++ b/@ether/library/Language/Inform7/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v inform7 >/dev/null 2>&1; then + exec inform7 "$@" +elif command -v ni >/dev/null 2>&1; then + exec ni "$@" +else + echo "Neither inform7 nor ni found in PATH." >&2; exit 1 +fi diff --git a/@ether/library/Language/Ink/check.sh b/@ether/library/Language/Ink/check.sh new file mode 100755 index 00000000..2d08b51a --- /dev/null +++ b/@ether/library/Language/Ink/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v cargo-contract >/dev/null 2>&1 diff --git a/@ether/library/Language/Ink/install.sh b/@ether/library/Language/Ink/install.sh new file mode 100755 index 00000000..d1b8f293 --- /dev/null +++ b/@ether/library/Language/Ink/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# ink!: Substrate/Polkadot smart contract language - https://use.ink/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/use-ink/cargo-contract" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/use-ink/cargo-contract.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + exit 0 +fi +if ! command -v cargo >/dev/null 2>&1; then + echo "Rust/Cargo is required. Install via: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh" >&2 + exit 1 +fi +cargo install cargo-contract diff --git a/@ether/library/Language/Ink/packages.sh b/@ether/library/Language/Ink/packages.sh new file mode 100755 index 00000000..89a83583 --- /dev/null +++ b/@ether/library/Language/Ink/packages.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="ink!" +REGISTRIES=( + "crates.io (Rust ecosystem): https://crates.io" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Note: ink! uses the Rust/Cargo ecosystem." + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v cargo &>/dev/null; then + cargo search ink-"$@" + else + echo "Visit: https://crates.io/search?q=ink-$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://crates.io/crates/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to Cargo.toml [dependencies]:" + echo " $1 = \"VERSION\"" + echo "" + echo "Then run: cargo build" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Ink/repl.sh b/@ether/library/Language/Ink/repl.sh new file mode 100755 index 00000000..fc372bc8 --- /dev/null +++ b/@ether/library/Language/Ink/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "ink! does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Ink/run.sh b/@ether/library/Language/Ink/run.sh new file mode 100755 index 00000000..2f98b2bb --- /dev/null +++ b/@ether/library/Language/Ink/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cargo contract build "$@" diff --git a/@ether/library/Language/Inko/check.sh b/@ether/library/Language/Inko/check.sh new file mode 100755 index 00000000..fd35909b --- /dev/null +++ b/@ether/library/Language/Inko/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v inko >/dev/null 2>&1 diff --git a/@ether/library/Language/Inko/install.sh b/@ether/library/Language/Inko/install.sh new file mode 100755 index 00000000..a4a8ac6b --- /dev/null +++ b/@ether/library/Language/Inko/install.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Inko from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/inko-lang/inko" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/inko-lang/inko.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release && cp target/release/inko "$HOME/.local/bin/" + exit 0 +fi +# Official install via ivm or cargo (https://inko-lang.org/install/) +if [[ "$(uname)" == "Darwin" ]]; then + brew install inko +elif command -v cargo >/dev/null 2>&1; then + cargo install inko +elif command -v apt-get >/dev/null 2>&1; then + # Use prebuilt from GitHub releases + VERSION=$(curl -sSL https://api.github.com/repos/inko-lang/inko/releases/latest | grep '"tag_name"' | sed 's/.*"v\(.*\)".*/\1/') + curl -fsSL "https://github.com/inko-lang/inko/releases/download/v${VERSION}/inko-${VERSION}-linux-amd64.tar.gz" -o /tmp/inko.tar.gz + sudo tar -xzf /tmp/inko.tar.gz -C /usr/local/bin/ + rm -f /tmp/inko.tar.gz +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm inko +else + echo "Unsupported package manager. Install Rust/Cargo and use: cargo install inko" >&2; exit 1 +fi diff --git a/@ether/library/Language/Inko/repl.sh b/@ether/library/Language/Inko/repl.sh new file mode 100755 index 00000000..a9f20790 --- /dev/null +++ b/@ether/library/Language/Inko/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Inko does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Inko/run.sh b/@ether/library/Language/Inko/run.sh new file mode 100755 index 00000000..823900a5 --- /dev/null +++ b/@ether/library/Language/Inko/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec inko run "$1" diff --git a/@ether/library/Language/Io/check.sh b/@ether/library/Language/Io/check.sh new file mode 100755 index 00000000..a396e0e3 --- /dev/null +++ b/@ether/library/Language/Io/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v io >/dev/null 2>&1 diff --git a/@ether/library/Language/Io/install.sh b/@ether/library/Language/Io/install.sh new file mode 100755 index 00000000..4c257b79 --- /dev/null +++ b/@ether/library/Language/Io/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +# Io language +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Io from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/IoLanguage/io" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/IoLanguage/io.git "$REPO_DIR" + fi + cd "$REPO_DIR" + mkdir -p build && cd build + cmake .. + make -j"$(nproc)" + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install io +elif command -v apt-get >/dev/null 2>&1; then + echo "Io is not in standard repos. Use --from-source to build from https://github.com/IoLanguage/io" >&2; exit 1 +elif command -v pacman >/dev/null 2>&1; then + echo "Check AUR for io-language: yay -S io-language" >&2; exit 1 +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Io/packages.sh b/@ether/library/Language/Io/packages.sh new file mode 100755 index 00000000..f706b593 --- /dev/null +++ b/@ether/library/Language/Io/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Io does not have an active package manager." +echo "Eerie (historical): https://github.com/IoLanguage/eerie" diff --git a/@ether/library/Language/Io/repl.sh b/@ether/library/Language/Io/repl.sh new file mode 100755 index 00000000..eb29b20b --- /dev/null +++ b/@ether/library/Language/Io/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec io diff --git a/@ether/library/Language/Io/run.sh b/@ether/library/Language/Io/run.sh new file mode 100755 index 00000000..a04a126e --- /dev/null +++ b/@ether/library/Language/Io/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec io "$@" diff --git a/@ether/library/Language/Ion/check.sh b/@ether/library/Language/Ion/check.sh new file mode 100755 index 00000000..4e28301a --- /dev/null +++ b/@ether/library/Language/Ion/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v ion >/dev/null 2>&1 diff --git a/@ether/library/Language/Ion/install.sh b/@ether/library/Language/Ion/install.sh new file mode 100755 index 00000000..69b67faf --- /dev/null +++ b/@ether/library/Language/Ion/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Ion shell from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/redox-os/ion" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/redox-os/ion.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release && cp target/release/ion "$HOME/.local/bin/" + exit 0 +fi +# Official install via cargo (https://doc.redox-os.org/ion-manual/) +cargo install ion-shell diff --git a/@ether/library/Language/Ion/repl.sh b/@ether/library/Language/Ion/repl.sh new file mode 100755 index 00000000..b065e478 --- /dev/null +++ b/@ether/library/Language/Ion/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ion diff --git a/@ether/library/Language/Ion/run.sh b/@ether/library/Language/Ion/run.sh new file mode 100755 index 00000000..96242bf3 --- /dev/null +++ b/@ether/library/Language/Ion/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ion "$1" diff --git a/@ether/library/Language/Isabelle/check.sh b/@ether/library/Language/Isabelle/check.sh new file mode 100755 index 00000000..4681699b --- /dev/null +++ b/@ether/library/Language/Isabelle/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v isabelle >/dev/null 2>&1 diff --git a/@ether/library/Language/Isabelle/install.sh b/@ether/library/Language/Isabelle/install.sh new file mode 100755 index 00000000..371f9159 --- /dev/null +++ b/@ether/library/Language/Isabelle/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official Isabelle installation (https://isabelle.in.tum.de/installation.html) +# Isabelle is distributed as a self-contained archive. +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask isabelle +elif [[ "$(uname)" == "Linux" ]]; then + ISABELLE_VERSION="Isabelle2024" + curl -fsSL "https://isabelle.in.tum.de/dist/${ISABELLE_VERSION}_linux.tar.gz" -o /tmp/isabelle.tar.gz + sudo tar -xzf /tmp/isabelle.tar.gz -C /opt/ + sudo ln -sf "/opt/${ISABELLE_VERSION}/bin/isabelle" /usr/local/bin/isabelle + rm -f /tmp/isabelle.tar.gz +else + echo "Unsupported platform." >&2; exit 1 +fi diff --git a/@ether/library/Language/Isabelle/packages.sh b/@ether/library/Language/Isabelle/packages.sh new file mode 100755 index 00000000..42f2e69a --- /dev/null +++ b/@ether/library/Language/Isabelle/packages.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://www.isa-afp.org" + +usage() { + echo "Isabelle Package Registry (Archive of Formal Proofs):" + echo " $REGISTRY" + echo + echo "Usage: packages.sh {search|info|install} " +} + +cmd_search() { + local q="$1" + echo "https://www.isa-afp.org/search?q=$q" +} + +cmd_info() { + local pkg="$1" + echo "https://www.isa-afp.org/entries/$pkg.html" +} + +cmd_install() { + local pkg="$1" + echo "To use an AFP entry in Isabelle:" + echo + echo " 1. Download the AFP: https://www.isa-afp.org/download/" + echo + echo " 2. Set AFP as component in etc/settings:" + echo " init_component /path/to/afp/thys" + echo + echo " 3. Import in your theory:" + echo " imports \"$pkg.Theory_Name\"" + echo + echo " Entry page: https://www.isa-afp.org/entries/$pkg.html" +} + +case "${1:-}" in + search) shift; cmd_search "$1" ;; + info) shift; cmd_info "$1" ;; + install) shift; cmd_install "$1" ;; + *) usage ;; +esac diff --git a/@ether/library/Language/Isabelle/repl.sh b/@ether/library/Language/Isabelle/repl.sh new file mode 100755 index 00000000..436814b8 --- /dev/null +++ b/@ether/library/Language/Isabelle/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec isabelle console diff --git a/@ether/library/Language/Isabelle/run.sh b/@ether/library/Language/Isabelle/run.sh new file mode 100755 index 00000000..dd215eca --- /dev/null +++ b/@ether/library/Language/Isabelle/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec isabelle process -T "$1" diff --git a/@ether/library/Language/Ivy/check.sh b/@ether/library/Language/Ivy/check.sh new file mode 100755 index 00000000..d360f3b4 --- /dev/null +++ b/@ether/library/Language/Ivy/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v ivy >/dev/null 2>&1 || command -v ivy_check >/dev/null 2>&1 diff --git a/@ether/library/Language/Ivy/install.sh b/@ether/library/Language/Ivy/install.sh new file mode 100755 index 00000000..d4307aaa --- /dev/null +++ b/@ether/library/Language/Ivy/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Ivy from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/microsoft/ivy" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/microsoft/ivy.git "$REPO_DIR" +fi +cd "$REPO_DIR" && pip install . diff --git a/@ether/library/Language/Ivy/repl.sh b/@ether/library/Language/Ivy/repl.sh new file mode 100755 index 00000000..392ce237 --- /dev/null +++ b/@ether/library/Language/Ivy/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Ivy does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Ivy/run.sh b/@ether/library/Language/Ivy/run.sh new file mode 100755 index 00000000..c688f2df --- /dev/null +++ b/@ether/library/Language/Ivy/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ivy_check "$1" diff --git a/@ether/library/Language/J/check.sh b/@ether/library/Language/J/check.sh new file mode 100755 index 00000000..849d1033 --- /dev/null +++ b/@ether/library/Language/J/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v jconsole >/dev/null 2>&1 || command -v ijconsole >/dev/null 2>&1 diff --git a/@ether/library/Language/J/install.sh b/@ether/library/Language/J/install.sh new file mode 100755 index 00000000..8b388852 --- /dev/null +++ b/@ether/library/Language/J/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# J language +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing J from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/jsoftware/jsource" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/jsoftware/jsource.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./build.sh + echo "Built. Add the bin directory to your PATH." >&2 + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask j +elif command -v apt-get >/dev/null 2>&1; then + echo "J is not in standard repos. Download from https://www.jsoftware.com/#/download" >&2; exit 1 +elif command -v pacman >/dev/null 2>&1; then + echo "Check AUR for j-language: yay -S j-language" >&2; exit 1 +else + echo "Download J from https://www.jsoftware.com/#/download" >&2; exit 1 +fi diff --git a/@ether/library/Language/J/packages.sh b/@ether/library/Language/J/packages.sh new file mode 100755 index 00000000..74c8452c --- /dev/null +++ b/@ether/library/Language/J/packages.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://code.jsoftware.com/wiki/Pacman" + +usage() { + echo "J Package Manager (Addon Manager / Pacman)" + echo "" + echo "Registry: $REGISTRY" + echo "" + echo "Usage: packages.sh [args]" + echo "" + echo "Commands:" + echo " search Search for addons" + echo " info Show addon information" + echo " install Install an addon" +} + +cmd_search() { + local query="$1" + echo "Search J addons:" + echo " $REGISTRY" + echo " https://code.jsoftware.com/wiki/Addons" + echo "" + echo "In the J console, run:" + echo " load 'pacman'" + echo " showlist ''" +} + +cmd_info() { + local addon="$1" + echo "Addon: $addon" + echo " https://code.jsoftware.com/wiki/Addons" + echo "" + echo "In the J console, run:" + echo " load 'pacman'" + echo " showpkg '$addon'" +} + +cmd_install() { + local addon="$1" + echo "In the J console, run:" + echo " load 'pacman'" + echo " install '$addon'" +} + +case "${1:-}" in + search) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh search "; exit 1; } + cmd_search "$1" + ;; + info) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh info "; exit 1; } + cmd_info "$1" + ;; + install) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh install "; exit 1; } + cmd_install "$1" + ;; + *) + usage + ;; +esac diff --git a/@ether/library/Language/J/repl.sh b/@ether/library/Language/J/repl.sh new file mode 100755 index 00000000..4374ce05 --- /dev/null +++ b/@ether/library/Language/J/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec jconsole diff --git a/@ether/library/Language/J/run.sh b/@ether/library/Language/J/run.sh new file mode 100755 index 00000000..8cf93de9 --- /dev/null +++ b/@ether/library/Language/J/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec jconsole "$@" diff --git a/@ether/library/Language/JSDoc/check.sh b/@ether/library/Language/JSDoc/check.sh new file mode 100755 index 00000000..0f7aeafe --- /dev/null +++ b/@ether/library/Language/JSDoc/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v jsdoc >/dev/null 2>&1 diff --git a/@ether/library/Language/JSDoc/install.sh b/@ether/library/Language/JSDoc/install.sh new file mode 100755 index 00000000..8661dda6 --- /dev/null +++ b/@ether/library/Language/JSDoc/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing JSDoc from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/jsdoc/jsdoc" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/jsdoc/jsdoc.git "$REPO_DIR" + fi + cd "$REPO_DIR" && npm install && npm link + exit 0 +fi +# Official install via npm (https://jsdoc.app/) +npm install -g jsdoc diff --git a/@ether/library/Language/JSDoc/repl.sh b/@ether/library/Language/JSDoc/repl.sh new file mode 100755 index 00000000..841b7afc --- /dev/null +++ b/@ether/library/Language/JSDoc/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "JSDoc is a documentation generator and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/JSDoc/run.sh b/@ether/library/Language/JSDoc/run.sh new file mode 100755 index 00000000..b1ac8553 --- /dev/null +++ b/@ether/library/Language/JSDoc/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec jsdoc "$1" diff --git a/@ether/library/Language/JSON/check.sh b/@ether/library/Language/JSON/check.sh new file mode 100755 index 00000000..91c10dfd --- /dev/null +++ b/@ether/library/Language/JSON/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# JSON is a data format; always available. +exit 0 diff --git a/@ether/library/Language/JSON/install.sh b/@ether/library/Language/JSON/install.sh new file mode 100755 index 00000000..b28480c1 --- /dev/null +++ b/@ether/library/Language/JSON/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +# JSON is a data format. No installation required. +# Optionally install jq for command-line processing. +if [[ "$(uname)" == "Darwin" ]]; then + brew install jq +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y jq +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y jq +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm jq +fi diff --git a/@ether/library/Language/JSON/repl.sh b/@ether/library/Language/JSON/repl.sh new file mode 100755 index 00000000..87c0d2d5 --- /dev/null +++ b/@ether/library/Language/JSON/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "JSON is a data format and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/JSON/run.sh b/@ether/library/Language/JSON/run.sh new file mode 100755 index 00000000..1f7c816d --- /dev/null +++ b/@ether/library/Language/JSON/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$1" diff --git a/@ether/library/Language/JSON5/check.sh b/@ether/library/Language/JSON5/check.sh new file mode 100755 index 00000000..33ddfe00 --- /dev/null +++ b/@ether/library/Language/JSON5/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# JSON5 is a data format; always available. +exit 0 diff --git a/@ether/library/Language/JSON5/install.sh b/@ether/library/Language/JSON5/install.sh new file mode 100755 index 00000000..c87104ed --- /dev/null +++ b/@ether/library/Language/JSON5/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# JSON5 is a data format. Install the reference parser via npm. +if command -v npm >/dev/null 2>&1; then + npm install -g json5 +else + echo "npm is required to install the JSON5 CLI. Install Node.js first." >&2 + exit 1 +fi diff --git a/@ether/library/Language/JSON5/repl.sh b/@ether/library/Language/JSON5/repl.sh new file mode 100755 index 00000000..2562a89e --- /dev/null +++ b/@ether/library/Language/JSON5/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "JSON5 is a data format and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/JSON5/run.sh b/@ether/library/Language/JSON5/run.sh new file mode 100755 index 00000000..1f7c816d --- /dev/null +++ b/@ether/library/Language/JSON5/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$1" diff --git a/@ether/library/Language/JSONLD/check.sh b/@ether/library/Language/JSONLD/check.sh new file mode 100755 index 00000000..dd1e84c0 --- /dev/null +++ b/@ether/library/Language/JSONLD/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# JSON-LD is a data format; always available. +exit 0 diff --git a/@ether/library/Language/JSONLD/install.sh b/@ether/library/Language/JSONLD/install.sh new file mode 100755 index 00000000..bfd73a92 --- /dev/null +++ b/@ether/library/Language/JSONLD/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# JSON-LD is a data format. No installation required. +echo "JSON-LD is a data format. No installation required." diff --git a/@ether/library/Language/JSONLD/repl.sh b/@ether/library/Language/JSONLD/repl.sh new file mode 100755 index 00000000..42a30cb1 --- /dev/null +++ b/@ether/library/Language/JSONLD/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "JSON-LD is a data format and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/JSONLD/run.sh b/@ether/library/Language/JSONLD/run.sh new file mode 100755 index 00000000..1f7c816d --- /dev/null +++ b/@ether/library/Language/JSONLD/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$1" diff --git a/@ether/library/Language/Janet/check.sh b/@ether/library/Language/Janet/check.sh new file mode 100755 index 00000000..18a670f5 --- /dev/null +++ b/@ether/library/Language/Janet/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v janet >/dev/null 2>&1 diff --git a/@ether/library/Language/Janet/install.sh b/@ether/library/Language/Janet/install.sh new file mode 100755 index 00000000..fa83be64 --- /dev/null +++ b/@ether/library/Language/Janet/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Janet from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/janet-lang/janet" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/janet-lang/janet.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make -j"$(nproc)" && sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install janet +elif command -v apt-get >/dev/null 2>&1; then + # Install from GitHub releases (https://janet-lang.org/docs/index.html) + VERSION=$(curl -sSL https://api.github.com/repos/janet-lang/janet/releases/latest | grep '"tag_name"' | sed 's/.*"v\(.*\)".*/\1/') + curl -fsSL "https://github.com/janet-lang/janet/releases/download/v${VERSION}/janet-v${VERSION}-linux-x64.tar.gz" -o /tmp/janet.tar.gz + sudo tar -xzf /tmp/janet.tar.gz -C /usr/local --strip-components=1 + rm -f /tmp/janet.tar.gz +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y janet +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm janet +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Janet/packages.sh b/@ether/library/Language/Janet/packages.sh new file mode 100755 index 00000000..3cf7dad5 --- /dev/null +++ b/@ether/library/Language/Janet/packages.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Janet" +REGISTRIES=( + "Janet Packages: https://github.com/janet-lang/pkgs" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://github.com/janet-lang/pkgs" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://github.com/janet-lang/pkgs" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + if command -v jpm &>/dev/null; then + jpm install "$1" + else + echo "jpm is not installed. Install Janet first: https://janet-lang.org" + fi + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Janet/repl.sh b/@ether/library/Language/Janet/repl.sh new file mode 100755 index 00000000..e45bb07a --- /dev/null +++ b/@ether/library/Language/Janet/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec janet diff --git a/@ether/library/Language/Janet/run.sh b/@ether/library/Language/Janet/run.sh new file mode 100755 index 00000000..968ee674 --- /dev/null +++ b/@ether/library/Language/Janet/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec janet "$1" diff --git a/@ether/library/Language/Janus/check.sh b/@ether/library/Language/Janus/check.sh new file mode 100755 index 00000000..33671458 --- /dev/null +++ b/@ether/library/Language/Janus/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v janus >/dev/null 2>&1 diff --git a/@ether/library/Language/Janus/install.sh b/@ether/library/Language/Janus/install.sh new file mode 100755 index 00000000..d6798d1a --- /dev/null +++ b/@ether/library/Language/Janus/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# Janus is a time-reversible computing programming language. +# Reference implementations exist as academic software. +# See: https://en.wikipedia.org/wiki/Janus_(time-reversible_computing_programming_language) +echo "Janus is an academic reversible programming language." >&2 +echo "No standardized package distribution is available." >&2 +echo "See: https://en.wikipedia.org/wiki/Janus_(time-reversible_computing_programming_language)" >&2 +exit 1 diff --git a/@ether/library/Language/Janus/repl.sh b/@ether/library/Language/Janus/repl.sh new file mode 100755 index 00000000..d60952db --- /dev/null +++ b/@ether/library/Language/Janus/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Janus does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Janus/run.sh b/@ether/library/Language/Janus/run.sh new file mode 100755 index 00000000..24ad0f82 --- /dev/null +++ b/@ether/library/Language/Janus/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Janus has no standardized runtime distribution." >&2 +exit 1 diff --git a/@ether/library/Language/Java/check.sh b/@ether/library/Language/Java/check.sh new file mode 100755 index 00000000..fe395c18 --- /dev/null +++ b/@ether/library/Language/Java/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v java >/dev/null 2>&1 && command -v javac >/dev/null 2>&1 diff --git a/@ether/library/Language/Java/install.sh b/@ether/library/Language/Java/install.sh new file mode 100755 index 00000000..26fc2ff6 --- /dev/null +++ b/@ether/library/Language/Java/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/openjdk/jdk" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/openjdk/jdk.git "$REPO_DIR" + fi + cd "$REPO_DIR" && bash configure && make images + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install openjdk +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y default-jdk +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y java-latest-openjdk-devel +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm jdk-openjdk +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Java/packages.sh b/@ether/library/Language/Java/packages.sh new file mode 100755 index 00000000..852c4307 --- /dev/null +++ b/@ether/library/Language/Java/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://search.maven.org" + +usage() { + echo "Java Package Registry:" + echo " $REGISTRY" + echo + echo "Usage: packages.sh {search|info|install} " +} + +cmd_search() { + local q="$1" + echo "https://search.maven.org/search?q=$q" +} + +cmd_info() { + local pkg="$1" + echo "https://search.maven.org/artifact/$pkg" +} + +cmd_install() { + local pkg="$1" + echo "Add to your project:" + echo + echo " Maven (pom.xml):" + echo " " + echo " GROUP_ID" + echo " $pkg" + echo " VERSION" + echo " " + echo + echo " Gradle (build.gradle):" + echo " implementation 'GROUP_ID:$pkg:VERSION'" + echo + echo " Find coordinates: https://search.maven.org/search?q=$pkg" +} + +case "${1:-}" in + search) shift; cmd_search "$1" ;; + info) shift; cmd_info "$1" ;; + install) shift; cmd_install "$1" ;; + *) usage ;; +esac diff --git a/@ether/library/Language/Java/repl.sh b/@ether/library/Language/Java/repl.sh new file mode 100755 index 00000000..9483b309 --- /dev/null +++ b/@ether/library/Language/Java/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec jshell diff --git a/@ether/library/Language/Java/run.sh b/@ether/library/Language/Java/run.sh new file mode 100755 index 00000000..b80a4eda --- /dev/null +++ b/@ether/library/Language/Java/run.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +if [[ -d "$file" ]]; then + cd "$file" + if [[ -f "pom.xml" ]]; then mvn exec:java + elif [[ -f "build.gradle" ]]; then gradle run + else echo "No build system found" >&2; exit 1; fi +else + javac "$file" && java "${file%.java}" +fi diff --git a/@ether/library/Language/JavaDoc/check.sh b/@ether/library/Language/JavaDoc/check.sh new file mode 100755 index 00000000..740185f1 --- /dev/null +++ b/@ether/library/Language/JavaDoc/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v javadoc >/dev/null 2>&1 diff --git a/@ether/library/Language/JavaDoc/install.sh b/@ether/library/Language/JavaDoc/install.sh new file mode 100755 index 00000000..63d14720 --- /dev/null +++ b/@ether/library/Language/JavaDoc/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# JavaDoc is included with the JDK. Install Java to get javadoc. +if [[ "$(uname)" == "Darwin" ]]; then + brew install openjdk +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y default-jdk +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y java-latest-openjdk-devel +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm jdk-openjdk +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/JavaDoc/repl.sh b/@ether/library/Language/JavaDoc/repl.sh new file mode 100755 index 00000000..3f4a5a79 --- /dev/null +++ b/@ether/library/Language/JavaDoc/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "JavaDoc is a documentation generator and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/JavaDoc/run.sh b/@ether/library/Language/JavaDoc/run.sh new file mode 100755 index 00000000..6d8acf97 --- /dev/null +++ b/@ether/library/Language/JavaDoc/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec javadoc "$1" diff --git a/@ether/library/Language/JavaScript/check.sh b/@ether/library/Language/JavaScript/check.sh new file mode 100755 index 00000000..b8c03a9a --- /dev/null +++ b/@ether/library/Language/JavaScript/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v node >/dev/null 2>&1 || command -v bun >/dev/null 2>&1 diff --git a/@ether/library/Language/JavaScript/install.sh b/@ether/library/Language/JavaScript/install.sh new file mode 100755 index 00000000..947fb12b --- /dev/null +++ b/@ether/library/Language/JavaScript/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "JavaScript runs via Node.js or Bun." +if ! command -v node >/dev/null 2>&1 && ! command -v bun >/dev/null 2>&1; then + echo "Installing Node.js..." + if [[ "$(uname)" == "Darwin" ]]; then + brew install node + elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm nodejs npm + elif command -v apt-get >/dev/null 2>&1; then + curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo bash - + sudo apt-get install -y nodejs + elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y nodejs npm + else + echo "Unsupported package manager." >&2; exit 1 + fi +fi diff --git a/@ether/library/Language/JavaScript/packages.sh b/@ether/library/Language/JavaScript/packages.sh new file mode 100755 index 00000000..8aa72e72 --- /dev/null +++ b/@ether/library/Language/JavaScript/packages.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="JavaScript" +REGISTRIES=( + "npm: https://www.npmjs.com" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + npm search "$@" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + npm info "$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + npm install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/JavaScript/repl.sh b/@ether/library/Language/JavaScript/repl.sh new file mode 100755 index 00000000..96c08b10 --- /dev/null +++ b/@ether/library/Language/JavaScript/repl.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +if command -v bun >/dev/null 2>&1; then + exec bun repl +else + exec node +fi diff --git a/@ether/library/Language/JavaScript/run.sh b/@ether/library/Language/JavaScript/run.sh new file mode 100755 index 00000000..de3b0812 --- /dev/null +++ b/@ether/library/Language/JavaScript/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +if command -v bun >/dev/null 2>&1; then + exec bun run "$@" +else + exec node "$@" +fi diff --git a/@ether/library/Language/JetBrainsMPS/check.sh b/@ether/library/Language/JetBrainsMPS/check.sh new file mode 100755 index 00000000..a7b4bcea --- /dev/null +++ b/@ether/library/Language/JetBrainsMPS/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v mps >/dev/null 2>&1 || [[ -d "/opt/MPS" ]] || [[ -d "$HOME/.local/share/JetBrains/MPS" ]] diff --git a/@ether/library/Language/JetBrainsMPS/install.sh b/@ether/library/Language/JetBrainsMPS/install.sh new file mode 100755 index 00000000..abc521d5 --- /dev/null +++ b/@ether/library/Language/JetBrainsMPS/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing JetBrains MPS from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/JetBrains/MPS" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/JetBrains/MPS.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./gradlew build + exit 0 +fi +# Official download from JetBrains (https://www.jetbrains.com/mps/download/) +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask mps +elif [[ "$(uname)" == "Linux" ]]; then + echo "Download JetBrains MPS from: https://www.jetbrains.com/mps/download/" + echo "Or use JetBrains Toolbox: https://www.jetbrains.com/toolbox-app/" + exit 1 +else + echo "Unsupported platform." >&2; exit 1 +fi diff --git a/@ether/library/Language/JetBrainsMPS/repl.sh b/@ether/library/Language/JetBrainsMPS/repl.sh new file mode 100755 index 00000000..c126b722 --- /dev/null +++ b/@ether/library/Language/JetBrainsMPS/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "JetBrains MPS is an IDE and does not have a CLI REPL." >&2 +exit 1 diff --git a/@ether/library/Language/JetBrainsMPS/run.sh b/@ether/library/Language/JetBrainsMPS/run.sh new file mode 100755 index 00000000..529a8d43 --- /dev/null +++ b/@ether/library/Language/JetBrainsMPS/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "JetBrains MPS is an IDE-based language workbench. Use the MPS GUI to run projects." >&2 +exit 1 diff --git a/@ether/library/Language/Joy/check.sh b/@ether/library/Language/Joy/check.sh new file mode 100755 index 00000000..493410ff --- /dev/null +++ b/@ether/library/Language/Joy/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import joy" >/dev/null 2>&1 || command -v joy >/dev/null 2>&1 diff --git a/@ether/library/Language/Joy/install.sh b/@ether/library/Language/Joy/install.sh new file mode 100755 index 00000000..4356c120 --- /dev/null +++ b/@ether/library/Language/Joy/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# Joy is a concatenative functional programming language. +# The reference implementation is available via Thun (a Python implementation). +# See: https://hypercubed.github.io/joy/ +pip install Thun || { + echo "Failed to install Joy (Thun). Ensure Python/pip is available." >&2 + exit 1 +} diff --git a/@ether/library/Language/Joy/repl.sh b/@ether/library/Language/Joy/repl.sh new file mode 100755 index 00000000..01b65f31 --- /dev/null +++ b/@ether/library/Language/Joy/repl.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v joy >/dev/null 2>&1; then + exec joy +else + exec python3 -m joy +fi diff --git a/@ether/library/Language/Joy/run.sh b/@ether/library/Language/Joy/run.sh new file mode 100755 index 00000000..9e3c04ce --- /dev/null +++ b/@ether/library/Language/Joy/run.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v joy >/dev/null 2>&1; then + exec joy "$1" +else + exec python3 -c " +from joy.library import initialize +from joy.joy import run +with open('$1') as f: + text = f.read() +stack = run(text, (), initialize()) +" +fi diff --git a/@ether/library/Language/Jsonnet/check.sh b/@ether/library/Language/Jsonnet/check.sh new file mode 100755 index 00000000..f1343b3d --- /dev/null +++ b/@ether/library/Language/Jsonnet/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v jsonnet >/dev/null 2>&1 diff --git a/@ether/library/Language/Jsonnet/install.sh b/@ether/library/Language/Jsonnet/install.sh new file mode 100755 index 00000000..2cbec6ce --- /dev/null +++ b/@ether/library/Language/Jsonnet/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Jsonnet from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/google/jsonnet" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/google/jsonnet.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make -j"$(nproc)" && sudo cp jsonnet jsonnetfmt /usr/local/bin/ + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install jsonnet +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y jsonnet +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y jsonnet +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm jsonnet +else + # Fallback: install Go implementation + go install github.com/google/go-jsonnet/cmd/jsonnet@latest +fi diff --git a/@ether/library/Language/Jsonnet/repl.sh b/@ether/library/Language/Jsonnet/repl.sh new file mode 100755 index 00000000..28bb5f22 --- /dev/null +++ b/@ether/library/Language/Jsonnet/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Jsonnet does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Jsonnet/run.sh b/@ether/library/Language/Jsonnet/run.sh new file mode 100755 index 00000000..6da3fad9 --- /dev/null +++ b/@ether/library/Language/Jsonnet/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec jsonnet "$1" diff --git a/@ether/library/Language/Julia/check.sh b/@ether/library/Language/Julia/check.sh new file mode 100755 index 00000000..72bdd043 --- /dev/null +++ b/@ether/library/Language/Julia/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v julia >/dev/null 2>&1 diff --git a/@ether/library/Language/Julia/install.sh b/@ether/library/Language/Julia/install.sh new file mode 100755 index 00000000..b0ae826e --- /dev/null +++ b/@ether/library/Language/Julia/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official method: juliaup - https://julialang.org/downloads/ +curl -fsSL https://install.julialang.org | sh -s -- -y diff --git a/@ether/library/Language/Julia/packages.sh b/@ether/library/Language/Julia/packages.sh new file mode 100755 index 00000000..9d351d1b --- /dev/null +++ b/@ether/library/Language/Julia/packages.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Julia" +REGISTRIES=( + "JuliaHub: https://juliahub.com" + "General Registry: https://github.com/JuliaRegistries/General" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v julia &>/dev/null; then + julia -e "using Pkg; results = Pkg.Registry.find(\"$1\"); for r in results; println(r); end" 2>/dev/null || echo "Visit: https://juliahub.com/ui/Packages?q=$1" + else + echo "Visit: https://juliahub.com/ui/Packages?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://juliahub.com/ui/Packages/General/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + julia -e "using Pkg; Pkg.add(\"$1\")" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Julia/repl.sh b/@ether/library/Language/Julia/repl.sh new file mode 100755 index 00000000..a568f365 --- /dev/null +++ b/@ether/library/Language/Julia/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec julia diff --git a/@ether/library/Language/Julia/run.sh b/@ether/library/Language/Julia/run.sh new file mode 100755 index 00000000..20eda9a6 --- /dev/null +++ b/@ether/library/Language/Julia/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec julia "$@" diff --git a/@ether/library/Language/Juvix/check.sh b/@ether/library/Language/Juvix/check.sh new file mode 100755 index 00000000..b5ccdfe4 --- /dev/null +++ b/@ether/library/Language/Juvix/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v juvix >/dev/null 2>&1 diff --git a/@ether/library/Language/Juvix/install.sh b/@ether/library/Language/Juvix/install.sh new file mode 100755 index 00000000..b91419be --- /dev/null +++ b/@ether/library/Language/Juvix/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Juvix from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/anoma/juvix" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/anoma/juvix.git "$REPO_DIR" + fi + cd "$REPO_DIR" && stack build && stack install + exit 0 +fi +# Official install (https://docs.juvix.org/latest/howto/installing/) +if [[ "$(uname)" == "Darwin" ]]; then + brew tap anoma/juvix && brew install juvix +else + # Install prebuilt from GitHub releases + ARCH=$(uname -m) + case "$ARCH" in + x86_64) JUVIX_ARCH="linux-x86_64" ;; + aarch64) JUVIX_ARCH="linux-aarch64" ;; + *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; + esac + VERSION=$(curl -sSL https://api.github.com/repos/anoma/juvix/releases/latest | grep '"tag_name"' | sed 's/.*"v\(.*\)".*/\1/') + curl -fsSL "https://github.com/anoma/juvix/releases/download/v${VERSION}/juvix-${JUVIX_ARCH}" -o /tmp/juvix + chmod +x /tmp/juvix && sudo mv /tmp/juvix /usr/local/bin/juvix +fi diff --git a/@ether/library/Language/Juvix/repl.sh b/@ether/library/Language/Juvix/repl.sh new file mode 100755 index 00000000..cefdabb4 --- /dev/null +++ b/@ether/library/Language/Juvix/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec juvix repl diff --git a/@ether/library/Language/Juvix/run.sh b/@ether/library/Language/Juvix/run.sh new file mode 100755 index 00000000..fa245c0e --- /dev/null +++ b/@ether/library/Language/Juvix/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec juvix eval "$1" diff --git a/@ether/library/Language/K/check.sh b/@ether/library/Language/K/check.sh new file mode 100755 index 00000000..7046d38e --- /dev/null +++ b/@ether/library/Language/K/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v q >/dev/null 2>&1 diff --git a/@ether/library/Language/K/install.sh b/@ether/library/Language/K/install.sh new file mode 100755 index 00000000..140a065f --- /dev/null +++ b/@ether/library/Language/K/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# K language (Kx/kdb+) +echo "K (kdb+/q) requires a license from Kx Systems." +echo "Download from: https://kx.com/developers/download-licenses/" +echo "" +echo "For the open-source oK interpreter, visit: https://github.com/JohnEarnest/ok" +echo "For ngn/k: https://codeberg.org/ngn/k" +echo "" +echo "After downloading, place the 'q' binary in your PATH." >&2 +exit 1 diff --git a/@ether/library/Language/K/packages.sh b/@ether/library/Language/K/packages.sh new file mode 100755 index 00000000..fb98540f --- /dev/null +++ b/@ether/library/Language/K/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "K does not have a standard package manager." +echo "Libraries are typically shared as source files." diff --git a/@ether/library/Language/K/repl.sh b/@ether/library/Language/K/repl.sh new file mode 100755 index 00000000..52a07beb --- /dev/null +++ b/@ether/library/Language/K/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec q diff --git a/@ether/library/Language/K/run.sh b/@ether/library/Language/K/run.sh new file mode 100755 index 00000000..ccebf793 --- /dev/null +++ b/@ether/library/Language/K/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec q "$@" diff --git a/@ether/library/Language/KFramework/check.sh b/@ether/library/Language/KFramework/check.sh new file mode 100755 index 00000000..4b621484 --- /dev/null +++ b/@ether/library/Language/KFramework/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v kompile >/dev/null 2>&1 diff --git a/@ether/library/Language/KFramework/install.sh b/@ether/library/Language/KFramework/install.sh new file mode 100755 index 00000000..a9ca05ac --- /dev/null +++ b/@ether/library/Language/KFramework/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing K Framework from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/kframework/k" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/kframework/k.git "$REPO_DIR" + fi + cd "$REPO_DIR" && mvn package -DskipTests + exit 0 +fi +# Official install (https://kframework.org/) +if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y curl + curl -fsSL https://github.com/kframework/k/releases/latest/download/kframework_amd64.deb -o /tmp/kframework.deb + sudo dpkg -i /tmp/kframework.deb || sudo apt-get install -f -y + rm -f /tmp/kframework.deb +elif [[ "$(uname)" == "Darwin" ]]; then + brew tap kframework/k && brew install kframework +elif command -v pacman >/dev/null 2>&1; then + curl -fsSL https://github.com/kframework/k/releases/latest/download/kframework-git-x86_64.pkg.tar.zst -o /tmp/kframework.pkg.tar.zst + sudo pacman -U --noconfirm /tmp/kframework.pkg.tar.zst + rm -f /tmp/kframework.pkg.tar.zst +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/KFramework/repl.sh b/@ether/library/Language/KFramework/repl.sh new file mode 100755 index 00000000..cc2dbe37 --- /dev/null +++ b/@ether/library/Language/KFramework/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "K Framework does not have a general-purpose REPL." >&2 +exit 1 diff --git a/@ether/library/Language/KFramework/run.sh b/@ether/library/Language/KFramework/run.sh new file mode 100755 index 00000000..200a01e1 --- /dev/null +++ b/@ether/library/Language/KFramework/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec krun "$1" diff --git a/@ether/library/Language/Keras/check.sh b/@ether/library/Language/Keras/check.sh new file mode 100755 index 00000000..643c1fe7 --- /dev/null +++ b/@ether/library/Language/Keras/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import keras" >/dev/null 2>&1 diff --git a/@ether/library/Language/Keras/install.sh b/@ether/library/Language/Keras/install.sh new file mode 100755 index 00000000..df910eab --- /dev/null +++ b/@ether/library/Language/Keras/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Keras from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/keras-team/keras" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/keras-team/keras.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install keras diff --git a/@ether/library/Language/Keras/repl.sh b/@ether/library/Language/Keras/repl.sh new file mode 100755 index 00000000..bd1903f9 --- /dev/null +++ b/@ether/library/Language/Keras/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import keras; import code; code.interact(local={'keras': keras})" diff --git a/@ether/library/Language/Keras/run.sh b/@ether/library/Language/Keras/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/Keras/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Kind/check.sh b/@ether/library/Language/Kind/check.sh new file mode 100755 index 00000000..04b45077 --- /dev/null +++ b/@ether/library/Language/Kind/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v kind >/dev/null 2>&1 diff --git a/@ether/library/Language/Kind/install.sh b/@ether/library/Language/Kind/install.sh new file mode 100755 index 00000000..cab62bba --- /dev/null +++ b/@ether/library/Language/Kind/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Kind from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/HigherOrderCO/Kind" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/HigherOrderCO/Kind.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release && cp target/release/kind "$HOME/.local/bin/" + exit 0 +fi +# Official install via cargo (https://github.com/HigherOrderCO/Kind) +cargo install kind-lang diff --git a/@ether/library/Language/Kind/repl.sh b/@ether/library/Language/Kind/repl.sh new file mode 100755 index 00000000..773f4b1d --- /dev/null +++ b/@ether/library/Language/Kind/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Kind does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Kind/run.sh b/@ether/library/Language/Kind/run.sh new file mode 100755 index 00000000..8ecee111 --- /dev/null +++ b/@ether/library/Language/Kind/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec kind run "$1" diff --git a/@ether/library/Language/Kitten/check.sh b/@ether/library/Language/Kitten/check.sh new file mode 100755 index 00000000..49727749 --- /dev/null +++ b/@ether/library/Language/Kitten/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v kitten >/dev/null 2>&1 diff --git a/@ether/library/Language/Kitten/install.sh b/@ether/library/Language/Kitten/install.sh new file mode 100755 index 00000000..7319f344 --- /dev/null +++ b/@ether/library/Language/Kitten/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Kitten - https://kittenlang.org/ - built from source (Haskell/Stack project) +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/evincarofautumn/kitten" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/evincarofautumn/kitten.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v stack >/dev/null 2>&1 || { echo "Haskell Stack required. Install via: curl -sSL https://get.haskellstack.org/ | sh" >&2; exit 1; } +stack build +stack install diff --git a/@ether/library/Language/Kitten/repl.sh b/@ether/library/Language/Kitten/repl.sh new file mode 100755 index 00000000..0c4d4172 --- /dev/null +++ b/@ether/library/Language/Kitten/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec kitten diff --git a/@ether/library/Language/Kitten/run.sh b/@ether/library/Language/Kitten/run.sh new file mode 100755 index 00000000..bce6b225 --- /dev/null +++ b/@ether/library/Language/Kitten/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec kitten "$1" diff --git a/@ether/library/Language/Koka/check.sh b/@ether/library/Language/Koka/check.sh new file mode 100755 index 00000000..e399ed43 --- /dev/null +++ b/@ether/library/Language/Koka/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v koka >/dev/null 2>&1 diff --git a/@ether/library/Language/Koka/install.sh b/@ether/library/Language/Koka/install.sh new file mode 100755 index 00000000..1f13dadf --- /dev/null +++ b/@ether/library/Language/Koka/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +# Koka - https://koka-lang.github.io/koka/doc/book.html#install +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/koka-lang/koka" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone --recursive https://github.com/koka-lang/koka.git "$REPO_DIR" + fi + cd "$REPO_DIR" + command -v stack >/dev/null 2>&1 || { echo "Haskell Stack required." >&2; exit 1; } + stack build + stack install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install koka +elif command -v apt-get >/dev/null 2>&1; then + curl -sSL https://github.com/koka-lang/koka/releases/latest/download/install.sh | sh +elif command -v dnf >/dev/null 2>&1; then + curl -sSL https://github.com/koka-lang/koka/releases/latest/download/install.sh | sh +elif command -v pacman >/dev/null 2>&1; then + curl -sSL https://github.com/koka-lang/koka/releases/latest/download/install.sh | sh +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/Koka/repl.sh b/@ether/library/Language/Koka/repl.sh new file mode 100755 index 00000000..26099130 --- /dev/null +++ b/@ether/library/Language/Koka/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec koka diff --git a/@ether/library/Language/Koka/run.sh b/@ether/library/Language/Koka/run.sh new file mode 100755 index 00000000..67f86f07 --- /dev/null +++ b/@ether/library/Language/Koka/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec koka "$1" diff --git a/@ether/library/Language/Kotlin/check.sh b/@ether/library/Language/Kotlin/check.sh new file mode 100755 index 00000000..f7c93124 --- /dev/null +++ b/@ether/library/Language/Kotlin/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v kotlin >/dev/null 2>&1 || command -v kotlinc >/dev/null 2>&1 diff --git a/@ether/library/Language/Kotlin/install.sh b/@ether/library/Language/Kotlin/install.sh new file mode 100755 index 00000000..13e6b07b --- /dev/null +++ b/@ether/library/Language/Kotlin/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official methods: SDKMAN!, Homebrew, Snap (https://kotlinlang.org/docs/command-line.html) +if [[ "$(uname)" == "Darwin" ]]; then + brew install kotlin +elif command -v sdk >/dev/null 2>&1; then + sdk install kotlin +elif command -v snap >/dev/null 2>&1; then + sudo snap install kotlin --classic +else + # Install via SDKMAN! (official primary method for Unix) + export SDKMAN_DIR="$HOME/.sdkman" + curl -s "https://get.sdkman.io" | bash + source "$SDKMAN_DIR/bin/sdkman-init.sh" + sdk install kotlin +fi diff --git a/@ether/library/Language/Kotlin/packages.sh b/@ether/library/Language/Kotlin/packages.sh new file mode 100755 index 00000000..c90d4c2a --- /dev/null +++ b/@ether/library/Language/Kotlin/packages.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Kotlin" +REGISTRIES=( + "Maven Central: https://search.maven.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://search.maven.org/search?q=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://search.maven.org/search?q=$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to build.gradle.kts:" + echo " dependencies {" + echo " implementation(\"GROUP:$1:VERSION\")" + echo " }" + echo "" + echo "Find the coordinates at: https://search.maven.org/search?q=$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Kotlin/repl.sh b/@ether/library/Language/Kotlin/repl.sh new file mode 100755 index 00000000..0a8482e6 --- /dev/null +++ b/@ether/library/Language/Kotlin/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec kotlinc diff --git a/@ether/library/Language/Kotlin/run.sh b/@ether/library/Language/Kotlin/run.sh new file mode 100755 index 00000000..49d1c0dc --- /dev/null +++ b/@ether/library/Language/Kotlin/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +kotlinc "$file" -include-runtime -d /tmp/kotlin_out.jar && java -jar /tmp/kotlin_out.jar +rm -f /tmp/kotlin_out.jar diff --git a/@ether/library/Language/LEGO/check.sh b/@ether/library/Language/LEGO/check.sh new file mode 100755 index 00000000..c8a2bfbf --- /dev/null +++ b/@ether/library/Language/LEGO/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v lego >/dev/null 2>&1 diff --git a/@ether/library/Language/LEGO/install.sh b/@ether/library/Language/LEGO/install.sh new file mode 100755 index 00000000..b1970c8e --- /dev/null +++ b/@ether/library/Language/LEGO/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# LEGO proof assistant - https://www.dcs.ed.ac.uk/home/lego/ +# Historical proof assistant from the University of Edinburgh. No modern package available. +echo "LEGO proof assistant is a historical system from the University of Edinburgh." +echo "No modern package or source repository is publicly available." +echo "See: https://www.dcs.ed.ac.uk/home/lego/" +exit 1 diff --git a/@ether/library/Language/LEGO/repl.sh b/@ether/library/Language/LEGO/repl.sh new file mode 100755 index 00000000..8ee7a9eb --- /dev/null +++ b/@ether/library/Language/LEGO/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec lego diff --git a/@ether/library/Language/LEGO/run.sh b/@ether/library/Language/LEGO/run.sh new file mode 100755 index 00000000..bd20068d --- /dev/null +++ b/@ether/library/Language/LEGO/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec lego "$1" diff --git a/@ether/library/Language/LFE/check.sh b/@ether/library/Language/LFE/check.sh new file mode 100755 index 00000000..d4e0feee --- /dev/null +++ b/@ether/library/Language/LFE/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v lfe >/dev/null 2>&1 diff --git a/@ether/library/Language/LFE/install.sh b/@ether/library/Language/LFE/install.sh new file mode 100755 index 00000000..001aa95c --- /dev/null +++ b/@ether/library/Language/LFE/install.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +# LFE - Lisp Flavoured Erlang +# Requires Erlang/OTP to be installed first +if ! command -v erl >/dev/null 2>&1; then + echo "Erlang/OTP is required. Install Erlang first." >&2 + exit 1 +fi +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing LFE from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/lfe/lfe" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/lfe/lfe.git "$REPO_DIR" + fi + cd "$REPO_DIR" + make + sudo make install + exit 0 +fi +# LFE is typically installed from source +echo "Installing LFE from source (default method)..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/lfe/lfe" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/lfe/lfe.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make +sudo make install diff --git a/@ether/library/Language/LFE/packages.sh b/@ether/library/Language/LFE/packages.sh new file mode 100755 index 00000000..cfbfb442 --- /dev/null +++ b/@ether/library/Language/LFE/packages.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://hex.pm" + +usage() { + echo "LFE Package Manager (hex.pm / Erlang ecosystem)" + echo "" + echo "LFE (Lisp Flavoured Erlang) uses the Erlang/hex ecosystem." + echo "" + echo "Registry: $REGISTRY" + echo "" + echo "Usage: packages.sh [args]" + echo "" + echo "Commands:" + echo " search Search for packages" + echo " info Show package information" + echo " install Install a package" +} + +cmd_search() { + if command -v rebar3 &>/dev/null; then + rebar3 hex search "$@" + else + local query="$1" + echo "rebar3 not found. Search online:" + echo " $REGISTRY/packages?search=$query" + fi +} + +cmd_info() { + local pkg="$1" + echo "Package info:" + echo " $REGISTRY/packages/$pkg" +} + +cmd_install() { + local pkg="$1" + echo "Add to your rebar.config deps:" + echo "" + echo " {deps, [" + echo " {$pkg, \"VERSION\"}" + echo " ]}." + echo "" + echo "Then run: rebar3 get-deps" + echo "" + echo "Find available versions at: $REGISTRY/packages/$pkg" +} + +case "${1:-}" in + search) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh search "; exit 1; } + cmd_search "$@" + ;; + info) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh info "; exit 1; } + cmd_info "$1" + ;; + install) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh install "; exit 1; } + cmd_install "$1" + ;; + *) + usage + ;; +esac diff --git a/@ether/library/Language/LFE/repl.sh b/@ether/library/Language/LFE/repl.sh new file mode 100755 index 00000000..b725f236 --- /dev/null +++ b/@ether/library/Language/LFE/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec lfe diff --git a/@ether/library/Language/LFE/run.sh b/@ether/library/Language/LFE/run.sh new file mode 100755 index 00000000..4035aa18 --- /dev/null +++ b/@ether/library/Language/LFE/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec lfe "$@" diff --git a/@ether/library/Language/LFSC/check.sh b/@ether/library/Language/LFSC/check.sh new file mode 100755 index 00000000..957bac6a --- /dev/null +++ b/@ether/library/Language/LFSC/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v lfscc >/dev/null 2>&1 diff --git a/@ether/library/Language/LFSC/install.sh b/@ether/library/Language/LFSC/install.sh new file mode 100755 index 00000000..a2cdb328 --- /dev/null +++ b/@ether/library/Language/LFSC/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# LFSC - Logical Framework with Side Conditions +# https://github.com/cvc5/LFSC +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/cvc5/LFSC" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/cvc5/LFSC.git "$REPO_DIR" +fi +cd "$REPO_DIR" +mkdir -p build && cd build +cmake .. && make -j"$(nproc)" +sudo make install diff --git a/@ether/library/Language/LFSC/repl.sh b/@ether/library/Language/LFSC/repl.sh new file mode 100755 index 00000000..337a8d4f --- /dev/null +++ b/@ether/library/Language/LFSC/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "LFSC does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/LFSC/run.sh b/@ether/library/Language/LFSC/run.sh new file mode 100755 index 00000000..e1561cb0 --- /dev/null +++ b/@ether/library/Language/LFSC/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec lfscc "$1" diff --git a/@ether/library/Language/LLVM/check.sh b/@ether/library/Language/LLVM/check.sh new file mode 100755 index 00000000..43e66c9c --- /dev/null +++ b/@ether/library/Language/LLVM/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v llc >/dev/null 2>&1 diff --git a/@ether/library/Language/LLVM/install.sh b/@ether/library/Language/LLVM/install.sh new file mode 100755 index 00000000..7eb465c8 --- /dev/null +++ b/@ether/library/Language/LLVM/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +# LLVM - https://llvm.org/docs/GettingStarted.html +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/llvm/llvm-project" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/llvm/llvm-project.git "$REPO_DIR" + fi + cd "$REPO_DIR" + cmake -S llvm -B build -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang" + cmake --build build -j"$(nproc)" + sudo cmake --install build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install llvm +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y llvm clang +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y llvm clang +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm llvm clang +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/LLVM/repl.sh b/@ether/library/Language/LLVM/repl.sh new file mode 100755 index 00000000..ca04d3e7 --- /dev/null +++ b/@ether/library/Language/LLVM/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "LLVM does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/LLVM/run.sh b/@ether/library/Language/LLVM/run.sh new file mode 100755 index 00000000..28f6e05b --- /dev/null +++ b/@ether/library/Language/LLVM/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec lli "$1" diff --git a/@ether/library/Language/LOLCODE/check.sh b/@ether/library/Language/LOLCODE/check.sh new file mode 100755 index 00000000..e9a3ebad --- /dev/null +++ b/@ether/library/Language/LOLCODE/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v lci >/dev/null 2>&1 diff --git a/@ether/library/Language/LOLCODE/install.sh b/@ether/library/Language/LOLCODE/install.sh new file mode 100755 index 00000000..5fddcadc --- /dev/null +++ b/@ether/library/Language/LOLCODE/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# LOLCODE - https://lolcode.org/ +# lci interpreter - https://github.com/justinmeza/lci +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/justinmeza/lci" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/justinmeza/lci.git "$REPO_DIR" +fi +cd "$REPO_DIR" +cmake . && make -j"$(nproc)" +sudo make install diff --git a/@ether/library/Language/LOLCODE/repl.sh b/@ether/library/Language/LOLCODE/repl.sh new file mode 100755 index 00000000..aad70ef4 --- /dev/null +++ b/@ether/library/Language/LOLCODE/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "LOLCODE does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/LOLCODE/run.sh b/@ether/library/Language/LOLCODE/run.sh new file mode 100755 index 00000000..b9c834c3 --- /dev/null +++ b/@ether/library/Language/LOLCODE/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec lci "$1" diff --git a/@ether/library/Language/LaTeX/check.sh b/@ether/library/Language/LaTeX/check.sh new file mode 100755 index 00000000..0804b41e --- /dev/null +++ b/@ether/library/Language/LaTeX/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v pdflatex >/dev/null 2>&1 diff --git a/@ether/library/Language/LaTeX/install.sh b/@ether/library/Language/LaTeX/install.sh new file mode 100755 index 00000000..e59768a0 --- /dev/null +++ b/@ether/library/Language/LaTeX/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# LaTeX - https://www.latex-project.org/get/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask mactex +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y texlive-full +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y texlive-scheme-full +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm texlive-most +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/LaTeX/repl.sh b/@ether/library/Language/LaTeX/repl.sh new file mode 100755 index 00000000..98b193bf --- /dev/null +++ b/@ether/library/Language/LaTeX/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "LaTeX does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/LaTeX/run.sh b/@ether/library/Language/LaTeX/run.sh new file mode 100755 index 00000000..54e030eb --- /dev/null +++ b/@ether/library/Language/LaTeX/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec pdflatex "$1" diff --git a/@ether/library/Language/Lambdapi/check.sh b/@ether/library/Language/Lambdapi/check.sh new file mode 100755 index 00000000..46845866 --- /dev/null +++ b/@ether/library/Language/Lambdapi/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v lambdapi >/dev/null 2>&1 diff --git a/@ether/library/Language/Lambdapi/install.sh b/@ether/library/Language/Lambdapi/install.sh new file mode 100755 index 00000000..93763e62 --- /dev/null +++ b/@ether/library/Language/Lambdapi/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +# Lambdapi - https://github.com/Deducteam/lambdapi +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Deducteam/lambdapi" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Deducteam/lambdapi.git "$REPO_DIR" + fi + cd "$REPO_DIR" + opam install . --deps-only -y + make + make install + exit 0 +fi +# Official install via opam +command -v opam >/dev/null 2>&1 || { echo "opam required. Install OCaml/opam first." >&2; exit 1; } +opam install lambdapi -y diff --git a/@ether/library/Language/Lambdapi/repl.sh b/@ether/library/Language/Lambdapi/repl.sh new file mode 100755 index 00000000..2897b16a --- /dev/null +++ b/@ether/library/Language/Lambdapi/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Lambdapi does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Lambdapi/run.sh b/@ether/library/Language/Lambdapi/run.sh new file mode 100755 index 00000000..a19f797e --- /dev/null +++ b/@ether/library/Language/Lambdapi/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec lambdapi check "$1" diff --git a/@ether/library/Language/Lea/check.sh b/@ether/library/Language/Lea/check.sh new file mode 100755 index 00000000..19667a6d --- /dev/null +++ b/@ether/library/Language/Lea/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import lea" 2>/dev/null diff --git a/@ether/library/Language/Lea/install.sh b/@ether/library/Language/Lea/install.sh new file mode 100755 index 00000000..15a5a071 --- /dev/null +++ b/@ether/library/Language/Lea/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# Lea - Python probabilistic programming library +# https://github.com/pfmoore/lea +pip install lea diff --git a/@ether/library/Language/Lea/repl.sh b/@ether/library/Language/Lea/repl.sh new file mode 100755 index 00000000..8f213a58 --- /dev/null +++ b/@ether/library/Language/Lea/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 -c "from lea import *; import code; code.interact(local=locals())" diff --git a/@ether/library/Language/Lea/run.sh b/@ether/library/Language/Lea/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/Lea/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Lean/check.sh b/@ether/library/Language/Lean/check.sh new file mode 100755 index 00000000..1df6f3b3 --- /dev/null +++ b/@ether/library/Language/Lean/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v lean >/dev/null 2>&1 diff --git a/@ether/library/Language/Lean/install.sh b/@ether/library/Language/Lean/install.sh new file mode 100755 index 00000000..6a65af64 --- /dev/null +++ b/@ether/library/Language/Lean/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/leanprover/lean4" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/leanprover/lean4.git "$REPO_DIR" + fi + cd "$REPO_DIR" && mkdir -p build && cd build && cmake .. && make -j"$(nproc)" + exit 0 +fi +curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh -s -- -y diff --git a/@ether/library/Language/Lean/packages.sh b/@ether/library/Language/Lean/packages.sh new file mode 100755 index 00000000..80f80246 --- /dev/null +++ b/@ether/library/Language/Lean/packages.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://reservoir.lean-lang.org" + +usage() { + echo "Lean Package Registry:" + echo " $REGISTRY" + echo + echo "Usage: packages.sh {search|info|install} " +} + +cmd_search() { + local q="$1" + echo "https://reservoir.lean-lang.org/?q=$q" +} + +cmd_info() { + local pkg="$1" + echo "https://reservoir.lean-lang.org/packages/$pkg" +} + +cmd_install() { + local pkg="$1" + echo "Add to lakefile.lean:" + echo + echo " require $pkg from git" + echo " \"https://github.com/OWNER/$pkg\" @ \"main\"" + echo + echo "Then run: lake update" + echo + echo "Find package details: https://reservoir.lean-lang.org/?q=$pkg" +} + +case "${1:-}" in + search) shift; cmd_search "$1" ;; + info) shift; cmd_info "$1" ;; + install) shift; cmd_install "$1" ;; + *) usage ;; +esac diff --git a/@ether/library/Language/Lean/repl.sh b/@ether/library/Language/Lean/repl.sh new file mode 100755 index 00000000..a45238ad --- /dev/null +++ b/@ether/library/Language/Lean/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec lean diff --git a/@ether/library/Language/Lean/run.sh b/@ether/library/Language/Lean/run.sh new file mode 100755 index 00000000..52f93bd3 --- /dev/null +++ b/@ether/library/Language/Lean/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec lean "$@" diff --git a/@ether/library/Language/Lem/check.sh b/@ether/library/Language/Lem/check.sh new file mode 100755 index 00000000..63294ca5 --- /dev/null +++ b/@ether/library/Language/Lem/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v lem >/dev/null 2>&1 diff --git a/@ether/library/Language/Lem/install.sh b/@ether/library/Language/Lem/install.sh new file mode 100755 index 00000000..2c6d6e77 --- /dev/null +++ b/@ether/library/Language/Lem/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +# Lem - https://github.com/rems-project/lem +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/rems-project/lem" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/rems-project/lem.git "$REPO_DIR" + fi + cd "$REPO_DIR" + opam install . --deps-only -y + make + make install + exit 0 +fi +# Official install via opam +command -v opam >/dev/null 2>&1 || { echo "opam required. Install OCaml/opam first." >&2; exit 1; } +opam install lem -y diff --git a/@ether/library/Language/Lem/repl.sh b/@ether/library/Language/Lem/repl.sh new file mode 100755 index 00000000..d1dbb716 --- /dev/null +++ b/@ether/library/Language/Lem/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Lem does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Lem/run.sh b/@ether/library/Language/Lem/run.sh new file mode 100755 index 00000000..39835959 --- /dev/null +++ b/@ether/library/Language/Lem/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec lem "$1" diff --git a/@ether/library/Language/Leo/check.sh b/@ether/library/Language/Leo/check.sh new file mode 100755 index 00000000..ce975716 --- /dev/null +++ b/@ether/library/Language/Leo/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v leo >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/leoprover/Leo-III" + ls "$REPO_DIR"/target/scala-*/Leo-III-assembly-*.jar >/dev/null 2>&1 +} diff --git a/@ether/library/Language/Leo/install.sh b/@ether/library/Language/Leo/install.sh new file mode 100755 index 00000000..cc2ddb3c --- /dev/null +++ b/@ether/library/Language/Leo/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Leo-III theorem prover - https://github.com/leoprover/Leo-III +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/leoprover/Leo-III" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/leoprover/Leo-III.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v sbt >/dev/null 2>&1 || { echo "sbt (Scala Build Tool) required." >&2; exit 1; } +sbt assembly +echo "Leo-III built. Run with: java -jar $REPO_DIR/target/scala-*/Leo-III-assembly-*.jar" diff --git a/@ether/library/Language/Leo/repl.sh b/@ether/library/Language/Leo/repl.sh new file mode 100755 index 00000000..3b9be588 --- /dev/null +++ b/@ether/library/Language/Leo/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Leo-III does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Leo/run.sh b/@ether/library/Language/Leo/run.sh new file mode 100755 index 00000000..1eba3f2c --- /dev/null +++ b/@ether/library/Language/Leo/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v leo >/dev/null 2>&1; then + exec leo "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/leoprover/Leo-III" + JAR=$(ls "$REPO_DIR"/target/scala-*/Leo-III-assembly-*.jar 2>/dev/null | head -1) + exec java -jar "$JAR" "$1" +fi diff --git a/@ether/library/Language/Less/check.sh b/@ether/library/Language/Less/check.sh new file mode 100755 index 00000000..2cb69683 --- /dev/null +++ b/@ether/library/Language/Less/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v lessc >/dev/null 2>&1 diff --git a/@ether/library/Language/Less/install.sh b/@ether/library/Language/Less/install.sh new file mode 100755 index 00000000..9d63f1b3 --- /dev/null +++ b/@ether/library/Language/Less/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# Less CSS - https://lesscss.org/ +npm install -g less diff --git a/@ether/library/Language/Less/repl.sh b/@ether/library/Language/Less/repl.sh new file mode 100755 index 00000000..e91220fc --- /dev/null +++ b/@ether/library/Language/Less/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Less does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Less/run.sh b/@ether/library/Language/Less/run.sh new file mode 100755 index 00000000..67c738ea --- /dev/null +++ b/@ether/library/Language/Less/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec lessc "$1" diff --git a/@ether/library/Language/Lets_Chance/check.sh b/@ether/library/Language/Lets_Chance/check.sh new file mode 100755 index 00000000..edfa3f91 --- /dev/null +++ b/@ether/library/Language/Lets_Chance/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Let's Chance runs within Scratch; no local command to check. +exit 1 diff --git a/@ether/library/Language/Lets_Chance/install.sh b/@ether/library/Language/Lets_Chance/install.sh new file mode 100755 index 00000000..468cb032 --- /dev/null +++ b/@ether/library/Language/Lets_Chance/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# Let's Chance - Playful probabilistic programming for children +# https://www.media.mit.edu/publications/letschance-playful-probabilistic-programming-for-children/ +# This is a Scratch-based (.sb3) educational environment. No standalone installer available. +echo "Let's Chance is a Scratch-based educational environment." +echo "It runs within the Scratch platform and has no standalone installer." +echo "See: https://www.media.mit.edu/publications/letschance-playful-probabilistic-programming-for-children/" +exit 1 diff --git a/@ether/library/Language/Lets_Chance/repl.sh b/@ether/library/Language/Lets_Chance/repl.sh new file mode 100755 index 00000000..9fcfcdeb --- /dev/null +++ b/@ether/library/Language/Lets_Chance/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Let's Chance does not have a command-line REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Lets_Chance/run.sh b/@ether/library/Language/Lets_Chance/run.sh new file mode 100755 index 00000000..f987ac31 --- /dev/null +++ b/@ether/library/Language/Lets_Chance/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Let's Chance files (.sb3) run within the Scratch platform." >&2 +exit 1 diff --git a/@ether/library/Language/Ligo/check.sh b/@ether/library/Language/Ligo/check.sh new file mode 100755 index 00000000..bd870656 --- /dev/null +++ b/@ether/library/Language/Ligo/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v ligo >/dev/null 2>&1 diff --git a/@ether/library/Language/Ligo/install.sh b/@ether/library/Language/Ligo/install.sh new file mode 100755 index 00000000..f26b9af0 --- /dev/null +++ b/@ether/library/Language/Ligo/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# LIGO: Tezos smart contract language - https://ligolang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/gitlab.com/ligolang/ligo" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://gitlab.com/ligolang/ligo.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install ligolang/ligo/ligo +elif command -v curl >/dev/null 2>&1; then + # Download static Linux binary + curl -fsSL https://ligolang.org/bin/linux/ligo -o /usr/local/bin/ligo 2>/dev/null || \ + sudo curl -fsSL https://ligolang.org/bin/linux/ligo -o /usr/local/bin/ligo + chmod +x /usr/local/bin/ligo 2>/dev/null || sudo chmod +x /usr/local/bin/ligo +else + echo "Download LIGO from: https://ligolang.org/docs/intro/installation" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Ligo/packages.sh b/@ether/library/Language/Ligo/packages.sh new file mode 100755 index 00000000..fc2ec0a5 --- /dev/null +++ b/@ether/library/Language/Ligo/packages.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Ligo" +REGISTRIES=( + "Ligo Packages: https://packages.ligolang.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v ligo &>/dev/null; then + ligo install --list 2>/dev/null || echo "Visit: https://packages.ligolang.org/?q=$1" + else + echo "Visit: https://packages.ligolang.org/?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://packages.ligolang.org/package/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + if command -v ligo &>/dev/null; then + ligo install "$1" + else + echo "ligo not found. Install it first:" + echo " https://ligolang.org/docs/intro/installation" + echo "" + echo "Then run: ligo install $1" + fi + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Ligo/repl.sh b/@ether/library/Language/Ligo/repl.sh new file mode 100755 index 00000000..9368625b --- /dev/null +++ b/@ether/library/Language/Ligo/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ligo repl diff --git a/@ether/library/Language/Ligo/run.sh b/@ether/library/Language/Ligo/run.sh new file mode 100755 index 00000000..d5108398 --- /dev/null +++ b/@ether/library/Language/Ligo/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ligo compile contract "$@" diff --git a/@ether/library/Language/LinearML/check.sh b/@ether/library/Language/LinearML/check.sh new file mode 100755 index 00000000..8fef97a5 --- /dev/null +++ b/@ether/library/Language/LinearML/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v linearml >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/pikatchu/LinearML" + [[ -x "$REPO_DIR/linearml" ]] +} diff --git a/@ether/library/Language/LinearML/install.sh b/@ether/library/Language/LinearML/install.sh new file mode 100755 index 00000000..6b358c1b --- /dev/null +++ b/@ether/library/Language/LinearML/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# LinearML - https://github.com/pikatchu/LinearML +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/pikatchu/LinearML" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/pikatchu/LinearML.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make diff --git a/@ether/library/Language/LinearML/repl.sh b/@ether/library/Language/LinearML/repl.sh new file mode 100755 index 00000000..54e9ca82 --- /dev/null +++ b/@ether/library/Language/LinearML/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "LinearML does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/LinearML/run.sh b/@ether/library/Language/LinearML/run.sh new file mode 100755 index 00000000..c5865d3b --- /dev/null +++ b/@ether/library/Language/LinearML/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v linearml >/dev/null 2>&1; then + exec linearml "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/pikatchu/LinearML" + exec "$REPO_DIR/linearml" "$1" +fi diff --git a/@ether/library/Language/Lobster/check.sh b/@ether/library/Language/Lobster/check.sh new file mode 100755 index 00000000..8583ddc6 --- /dev/null +++ b/@ether/library/Language/Lobster/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v lobster >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/aardappel/lobster" + [[ -x "$REPO_DIR/dev/lobster" ]] +} diff --git a/@ether/library/Language/Lobster/install.sh b/@ether/library/Language/Lobster/install.sh new file mode 100755 index 00000000..4c56d1f6 --- /dev/null +++ b/@ether/library/Language/Lobster/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +# Lobster - https://strlen.com/lobster/ +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/aardappel/lobster" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/aardappel/lobster.git "$REPO_DIR" +fi +cd "$REPO_DIR/dev" +cmake -DCMAKE_BUILD_TYPE=Release . && make -j"$(nproc)" +echo "Lobster built at: $REPO_DIR/dev/lobster" diff --git a/@ether/library/Language/Lobster/repl.sh b/@ether/library/Language/Lobster/repl.sh new file mode 100755 index 00000000..a5c8e35c --- /dev/null +++ b/@ether/library/Language/Lobster/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Lobster does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Lobster/run.sh b/@ether/library/Language/Lobster/run.sh new file mode 100755 index 00000000..bc91052d --- /dev/null +++ b/@ether/library/Language/Lobster/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v lobster >/dev/null 2>&1; then + exec lobster "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/aardappel/lobster" + exec "$REPO_DIR/dev/lobster" "$1" +fi diff --git a/@ether/library/Language/Lowlevel_Firstorder_PPL/check.sh b/@ether/library/Language/Lowlevel_Firstorder_PPL/check.sh new file mode 100755 index 00000000..6182266a --- /dev/null +++ b/@ether/library/Language/Lowlevel_Firstorder_PPL/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import pylfppl" 2>/dev/null diff --git a/@ether/library/Language/Lowlevel_Firstorder_PPL/install.sh b/@ether/library/Language/Lowlevel_Firstorder_PPL/install.sh new file mode 100755 index 00000000..24aad1ba --- /dev/null +++ b/@ether/library/Language/Lowlevel_Firstorder_PPL/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# Low-level First-order PPL - https://github.com/bayesianbrad/PyLFPPL +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/bayesianbrad/PyLFPPL" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/bayesianbrad/PyLFPPL.git "$REPO_DIR" +fi +cd "$REPO_DIR" +pip install -e . diff --git a/@ether/library/Language/Lowlevel_Firstorder_PPL/repl.sh b/@ether/library/Language/Lowlevel_Firstorder_PPL/repl.sh new file mode 100755 index 00000000..1af4d1c9 --- /dev/null +++ b/@ether/library/Language/Lowlevel_Firstorder_PPL/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 -c "from pylfppl import *; import code; code.interact(local=locals())" diff --git a/@ether/library/Language/Lowlevel_Firstorder_PPL/run.sh b/@ether/library/Language/Lowlevel_Firstorder_PPL/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/Lowlevel_Firstorder_PPL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Lua/check.sh b/@ether/library/Language/Lua/check.sh new file mode 100755 index 00000000..776ff499 --- /dev/null +++ b/@ether/library/Language/Lua/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v lua >/dev/null 2>&1 || command -v lua5.4 >/dev/null 2>&1 diff --git a/@ether/library/Language/Lua/install.sh b/@ether/library/Language/Lua/install.sh new file mode 100755 index 00000000..b96a9b6d --- /dev/null +++ b/@ether/library/Language/Lua/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install lua +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y lua5.4 +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y lua +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm lua +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Lua/packages.sh b/@ether/library/Language/Lua/packages.sh new file mode 100755 index 00000000..ec4d0f4c --- /dev/null +++ b/@ether/library/Language/Lua/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Lua" +REGISTRIES=( + "LuaRocks: https://luarocks.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v luarocks &>/dev/null; then + luarocks search "$@" + else + echo "Visit: https://luarocks.org/search?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v luarocks &>/dev/null; then + luarocks show "$1" + else + echo "Visit: https://luarocks.org/modules?q=$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + luarocks install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Lua/repl.sh b/@ether/library/Language/Lua/repl.sh new file mode 100755 index 00000000..a8189bd5 --- /dev/null +++ b/@ether/library/Language/Lua/repl.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +if command -v lua >/dev/null 2>&1; then + exec lua +else + exec lua5.4 +fi diff --git a/@ether/library/Language/Lua/run.sh b/@ether/library/Language/Lua/run.sh new file mode 100755 index 00000000..f0b66992 --- /dev/null +++ b/@ether/library/Language/Lua/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +if command -v lua >/dev/null 2>&1; then + exec lua "$@" +else + exec lua5.4 "$@" +fi diff --git a/@ether/library/Language/Luau/check.sh b/@ether/library/Language/Luau/check.sh new file mode 100755 index 00000000..faecdf5c --- /dev/null +++ b/@ether/library/Language/Luau/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v luau >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/luau-lang/luau" + [[ -x "$REPO_DIR/build/luau" ]] +} diff --git a/@ether/library/Language/Luau/install.sh b/@ether/library/Language/Luau/install.sh new file mode 100755 index 00000000..14f2dfc9 --- /dev/null +++ b/@ether/library/Language/Luau/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Luau - https://luau.org/ +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/luau-lang/luau" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/luau-lang/luau.git "$REPO_DIR" +fi +cd "$REPO_DIR" +mkdir -p build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Release && cmake --build . --target Luau.Repl.CLI -j"$(nproc)" +echo "Luau built at: $REPO_DIR/build" diff --git a/@ether/library/Language/Luau/packages.sh b/@ether/library/Language/Luau/packages.sh new file mode 100755 index 00000000..e80d6f6c --- /dev/null +++ b/@ether/library/Language/Luau/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Luau" +REGISTRIES=( + "LuaRocks: https://luarocks.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME (uses Lua ecosystem)" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v luarocks &>/dev/null; then + luarocks search "$@" + else + echo "Visit: https://luarocks.org/search?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v luarocks &>/dev/null; then + luarocks show "$1" + else + echo "Visit: https://luarocks.org/modules?q=$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + luarocks install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Luau/repl.sh b/@ether/library/Language/Luau/repl.sh new file mode 100755 index 00000000..310a1a5e --- /dev/null +++ b/@ether/library/Language/Luau/repl.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +if command -v luau >/dev/null 2>&1; then + exec luau +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/luau-lang/luau" + exec "$REPO_DIR/build/luau" +fi diff --git a/@ether/library/Language/Luau/run.sh b/@ether/library/Language/Luau/run.sh new file mode 100755 index 00000000..7f58c08b --- /dev/null +++ b/@ether/library/Language/Luau/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v luau >/dev/null 2>&1; then + exec luau "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/luau-lang/luau" + exec "$REPO_DIR/build/luau" "$1" +fi diff --git a/@ether/library/Language/Lustre/check.sh b/@ether/library/Language/Lustre/check.sh new file mode 100755 index 00000000..a7a45a54 --- /dev/null +++ b/@ether/library/Language/Lustre/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v lv6 >/dev/null 2>&1 || command -v luciole >/dev/null 2>&1 diff --git a/@ether/library/Language/Lustre/install.sh b/@ether/library/Language/Lustre/install.sh new file mode 100755 index 00000000..223c23f4 --- /dev/null +++ b/@ether/library/Language/Lustre/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Lustre - synchronous dataflow programming language +# https://www-verimag.imag.fr/The-Lustre-Programming-Language-and +# The reference compiler (lustre-v6/lv6) is available via opam or academic distribution. +if command -v opam >/dev/null 2>&1; then + opam install lv6 -y 2>/dev/null || { + echo "lv6 not available in current opam repos." + echo "See: https://www-verimag.imag.fr/The-Lustre-Programming-Language-and" + exit 1 + } +else + echo "Lustre compiler requires opam or manual installation." + echo "See: https://www-verimag.imag.fr/The-Lustre-Programming-Language-and" + exit 1 +fi diff --git a/@ether/library/Language/Lustre/repl.sh b/@ether/library/Language/Lustre/repl.sh new file mode 100755 index 00000000..87db59e2 --- /dev/null +++ b/@ether/library/Language/Lustre/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Lustre does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Lustre/run.sh b/@ether/library/Language/Lustre/run.sh new file mode 100755 index 00000000..167939f3 --- /dev/null +++ b/@ether/library/Language/Lustre/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec lv6 "$1" diff --git a/@ether/library/Language/M4/check.sh b/@ether/library/Language/M4/check.sh new file mode 100755 index 00000000..2da03917 --- /dev/null +++ b/@ether/library/Language/M4/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v m4 >/dev/null 2>&1 diff --git a/@ether/library/Language/M4/install.sh b/@ether/library/Language/M4/install.sh new file mode 100755 index 00000000..eb8cea02 --- /dev/null +++ b/@ether/library/Language/M4/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# M4 - GNU macro processor - https://www.gnu.org/software/m4/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install m4 +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y m4 +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y m4 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm m4 +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/M4/repl.sh b/@ether/library/Language/M4/repl.sh new file mode 100755 index 00000000..dee23fd5 --- /dev/null +++ b/@ether/library/Language/M4/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec m4 diff --git a/@ether/library/Language/M4/run.sh b/@ether/library/Language/M4/run.sh new file mode 100755 index 00000000..f59144cb --- /dev/null +++ b/@ether/library/Language/M4/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec m4 "$1" diff --git a/@ether/library/Language/MATLAB/check.sh b/@ether/library/Language/MATLAB/check.sh new file mode 100755 index 00000000..96e23008 --- /dev/null +++ b/@ether/library/Language/MATLAB/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v matlab >/dev/null 2>&1 diff --git a/@ether/library/Language/MATLAB/install.sh b/@ether/library/Language/MATLAB/install.sh new file mode 100755 index 00000000..8e406d9f --- /dev/null +++ b/@ether/library/Language/MATLAB/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# MATLAB - commercial product from MathWorks +# https://www.mathworks.com/products/matlab.html +echo "MATLAB is a commercial product from MathWorks." +echo "Download the installer from: https://www.mathworks.com/downloads/" +echo "A valid license is required." +exit 1 diff --git a/@ether/library/Language/MATLAB/repl.sh b/@ether/library/Language/MATLAB/repl.sh new file mode 100755 index 00000000..1bcb5ae2 --- /dev/null +++ b/@ether/library/Language/MATLAB/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec matlab -nodesktop -nosplash diff --git a/@ether/library/Language/MATLAB/run.sh b/@ether/library/Language/MATLAB/run.sh new file mode 100755 index 00000000..9f985a59 --- /dev/null +++ b/@ether/library/Language/MATLAB/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec matlab -batch "run('$1')" diff --git a/@ether/library/Language/MINLOG/check.sh b/@ether/library/Language/MINLOG/check.sh new file mode 100755 index 00000000..986ac80a --- /dev/null +++ b/@ether/library/Language/MINLOG/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v minlog >/dev/null 2>&1 diff --git a/@ether/library/Language/MINLOG/install.sh b/@ether/library/Language/MINLOG/install.sh new file mode 100755 index 00000000..05ca3fb5 --- /dev/null +++ b/@ether/library/Language/MINLOG/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# MINLOG - http://www.minlog-system.de/ +# Requires Scheme (Chez Scheme or Petite Chez Scheme) +echo "MINLOG is distributed from http://www.minlog-system.de/" +echo "Download the latest version and follow the installation instructions." +echo "Requires Chez Scheme or Petite Chez Scheme." +if [[ "$(uname)" == "Darwin" ]]; then + brew install chezscheme +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y chezscheme +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm chez-scheme +fi diff --git a/@ether/library/Language/MINLOG/repl.sh b/@ether/library/Language/MINLOG/repl.sh new file mode 100755 index 00000000..8269fbaf --- /dev/null +++ b/@ether/library/Language/MINLOG/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec minlog diff --git a/@ether/library/Language/MINLOG/run.sh b/@ether/library/Language/MINLOG/run.sh new file mode 100755 index 00000000..321c2382 --- /dev/null +++ b/@ether/library/Language/MINLOG/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec minlog "$1" diff --git a/@ether/library/Language/MIPSAssembly/check.sh b/@ether/library/Language/MIPSAssembly/check.sh new file mode 100755 index 00000000..39919236 --- /dev/null +++ b/@ether/library/Language/MIPSAssembly/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v spim >/dev/null 2>&1 diff --git a/@ether/library/Language/MIPSAssembly/install.sh b/@ether/library/Language/MIPSAssembly/install.sh new file mode 100755 index 00000000..87229c88 --- /dev/null +++ b/@ether/library/Language/MIPSAssembly/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# MIPS Assembly - install SPIM simulator +# https://en.wikipedia.org/wiki/MIPS_architecture +if [[ "$(uname)" == "Darwin" ]]; then + brew install spim +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y spim +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y spim +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm spim +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/MIPSAssembly/repl.sh b/@ether/library/Language/MIPSAssembly/repl.sh new file mode 100755 index 00000000..e00977e9 --- /dev/null +++ b/@ether/library/Language/MIPSAssembly/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec spim diff --git a/@ether/library/Language/MIPSAssembly/run.sh b/@ether/library/Language/MIPSAssembly/run.sh new file mode 100755 index 00000000..ed172962 --- /dev/null +++ b/@ether/library/Language/MIPSAssembly/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec spim -file "$1" diff --git a/@ether/library/Language/MQT/check.sh b/@ether/library/Language/MQT/check.sh new file mode 100755 index 00000000..9cdd5f9e --- /dev/null +++ b/@ether/library/Language/MQT/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import mqt" 2>/dev/null diff --git a/@ether/library/Language/MQT/install.sh b/@ether/library/Language/MQT/install.sh new file mode 100755 index 00000000..c3ce59b1 --- /dev/null +++ b/@ether/library/Language/MQT/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# MQT - Munich Quantum Toolkit +# https://github.com/cda-tum/mqt +pip install mqt.core mqt.qmap mqt.ddsim diff --git a/@ether/library/Language/MQT/repl.sh b/@ether/library/Language/MQT/repl.sh new file mode 100755 index 00000000..98aa674d --- /dev/null +++ b/@ether/library/Language/MQT/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 -c "from mqt.core import *; import code; code.interact(local=locals())" diff --git a/@ether/library/Language/MQT/run.sh b/@ether/library/Language/MQT/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/MQT/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/MSL/check.sh b/@ether/library/Language/MSL/check.sh new file mode 100755 index 00000000..f65277d2 --- /dev/null +++ b/@ether/library/Language/MSL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v metal >/dev/null 2>&1 || command -v xcrun >/dev/null 2>&1 diff --git a/@ether/library/Language/MSL/install.sh b/@ether/library/Language/MSL/install.sh new file mode 100755 index 00000000..a49b0840 --- /dev/null +++ b/@ether/library/Language/MSL/install.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + if ! xcode-select -p >/dev/null 2>&1; then + xcode-select --install + fi + echo "MSL (Metal Shading Language) is available via Xcode command line tools." +else + echo "MSL (Metal Shading Language) is only supported on macOS." >&2; exit 1 +fi diff --git a/@ether/library/Language/MSL/repl.sh b/@ether/library/Language/MSL/repl.sh new file mode 100755 index 00000000..a3c876ca --- /dev/null +++ b/@ether/library/Language/MSL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "MSL (Metal Shading Language) does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/MSL/run.sh b/@ether/library/Language/MSL/run.sh new file mode 100755 index 00000000..ecdaba35 --- /dev/null +++ b/@ether/library/Language/MSL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec xcrun -sdk macosx metal "$@" diff --git a/@ether/library/Language/Magmide/check.sh b/@ether/library/Language/Magmide/check.sh new file mode 100755 index 00000000..d1141f26 --- /dev/null +++ b/@ether/library/Language/Magmide/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v magmide >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/magmide/magmide" + [[ -x "$REPO_DIR/target/release/magmide" ]] +} diff --git a/@ether/library/Language/Magmide/install.sh b/@ether/library/Language/Magmide/install.sh new file mode 100755 index 00000000..dbc644f8 --- /dev/null +++ b/@ether/library/Language/Magmide/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Magmide - https://github.com/magmide/magmide +# Research proof language (work in progress) +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/magmide/magmide" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/magmide/magmide.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v cargo >/dev/null 2>&1 || { echo "Rust/Cargo required." >&2; exit 1; } +cargo build --release diff --git a/@ether/library/Language/Magmide/repl.sh b/@ether/library/Language/Magmide/repl.sh new file mode 100755 index 00000000..b6b585d2 --- /dev/null +++ b/@ether/library/Language/Magmide/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Magmide does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Magmide/run.sh b/@ether/library/Language/Magmide/run.sh new file mode 100755 index 00000000..3a62e342 --- /dev/null +++ b/@ether/library/Language/Magmide/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v magmide >/dev/null 2>&1; then + exec magmide "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/magmide/magmide" + exec "$REPO_DIR/target/release/magmide" "$1" +fi diff --git a/@ether/library/Language/Make/check.sh b/@ether/library/Language/Make/check.sh new file mode 100755 index 00000000..816bcdd5 --- /dev/null +++ b/@ether/library/Language/Make/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v make >/dev/null 2>&1 diff --git a/@ether/library/Language/Make/install.sh b/@ether/library/Language/Make/install.sh new file mode 100755 index 00000000..5ed4e454 --- /dev/null +++ b/@ether/library/Language/Make/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# GNU Make - https://www.gnu.org/software/make/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install make +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y make +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y make +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm make +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Make/repl.sh b/@ether/library/Language/Make/repl.sh new file mode 100755 index 00000000..d573b8e0 --- /dev/null +++ b/@ether/library/Language/Make/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Make does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Make/run.sh b/@ether/library/Language/Make/run.sh new file mode 100755 index 00000000..7c8d2f6d --- /dev/null +++ b/@ether/library/Language/Make/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec make -f "$1" diff --git a/@ether/library/Language/Malbolge/check.sh b/@ether/library/Language/Malbolge/check.sh new file mode 100755 index 00000000..34b4b960 --- /dev/null +++ b/@ether/library/Language/Malbolge/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v malbolge >/dev/null 2>&1 diff --git a/@ether/library/Language/Malbolge/install.sh b/@ether/library/Language/Malbolge/install.sh new file mode 100755 index 00000000..3918fb68 --- /dev/null +++ b/@ether/library/Language/Malbolge/install.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail +# Malbolge - esoteric programming language +# https://esolangs.org/wiki/Malbolge +# No official package; compile the reference interpreter from source. +TMPDIR="${ETHER_EXTERNAL_DIR:-/tmp}/malbolge" +mkdir -p "$TMPDIR" +cat > "$TMPDIR/malbolge.c" << 'CEOF' +/* Malbolge reference interpreter by Andrew Cooke */ +#include +#include +#include +#include +#define MAX 59049 +unsigned int mem[MAX]; +static const char xlat1[] = "+b(29e*j1VMEKLyC})8&m#~W>qxdRp0wkrUo[D7,XTcA\"lI.v%{gJh4G\\-=O@5`_3iU!pyi19telementation0telementation2telementation6jC#bTv^);telementation"; +int main(int argc, char **argv) { + FILE *f; int i; unsigned int a=0, c=0, d=0; + if (argc != 2) { fprintf(stderr, "Usage: malbolge \n"); return 1; } + f = fopen(argv[1], "r"); + if (!f) { perror(argv[1]); return 1; } + for (i=0; i 126) break; + switch ((mem[c] + c) % 94) { + case 4: c = mem[d]; break; + case 5: printf("%c", a % 256); break; + case 23: a = getchar(); if (a == EOF) a = MAX-1; break; + case 39: { unsigned int t = mem[d]; a = t = t/3 + t%3*MAX/3; mem[d] = t; } break; + case 40: d = mem[d]; break; + case 62: { unsigned int t = mem[d]; a = t = t/3 + t%3*MAX/3; mem[d] = t; } break; + case 68: break; + case 81: return 0; + } + mem[c] = xlat2[mem[c]-33]; + c = (c+1) % MAX; + d = (d+1) % MAX; + } + return 0; +} +CEOF +cc -O2 -o "$TMPDIR/malbolge" "$TMPDIR/malbolge.c" +sudo cp "$TMPDIR/malbolge" /usr/local/bin/malbolge 2>/dev/null || \ + cp "$TMPDIR/malbolge" "$HOME/.local/bin/malbolge" 2>/dev/null || \ + echo "Built at: $TMPDIR/malbolge" diff --git a/@ether/library/Language/Malbolge/repl.sh b/@ether/library/Language/Malbolge/repl.sh new file mode 100755 index 00000000..bc1c4fcf --- /dev/null +++ b/@ether/library/Language/Malbolge/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Malbolge does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Malbolge/run.sh b/@ether/library/Language/Malbolge/run.sh new file mode 100755 index 00000000..d90e79aa --- /dev/null +++ b/@ether/library/Language/Malbolge/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec malbolge "$1" diff --git a/@ether/library/Language/Maple/check.sh b/@ether/library/Language/Maple/check.sh new file mode 100755 index 00000000..bf94c338 --- /dev/null +++ b/@ether/library/Language/Maple/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v maple >/dev/null 2>&1 diff --git a/@ether/library/Language/Maple/install.sh b/@ether/library/Language/Maple/install.sh new file mode 100755 index 00000000..48df2c05 --- /dev/null +++ b/@ether/library/Language/Maple/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# Maple - commercial computer algebra system +# https://www.maplesoft.com/products/maple/ +echo "Maple is a commercial product from Maplesoft." +echo "Download the installer from: https://www.maplesoft.com/products/maple/" +echo "A valid license is required." +exit 1 diff --git a/@ether/library/Language/Maple/repl.sh b/@ether/library/Language/Maple/repl.sh new file mode 100755 index 00000000..010acbe9 --- /dev/null +++ b/@ether/library/Language/Maple/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec maple diff --git a/@ether/library/Language/Maple/run.sh b/@ether/library/Language/Maple/run.sh new file mode 100755 index 00000000..9d3b81c4 --- /dev/null +++ b/@ether/library/Language/Maple/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec maple "$1" diff --git a/@ether/library/Language/Markdown/check.sh b/@ether/library/Language/Markdown/check.sh new file mode 100755 index 00000000..50f11d14 --- /dev/null +++ b/@ether/library/Language/Markdown/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Markdown is a markup format; always available. +exit 0 diff --git a/@ether/library/Language/Markdown/install.sh b/@ether/library/Language/Markdown/install.sh new file mode 100755 index 00000000..bf3afb61 --- /dev/null +++ b/@ether/library/Language/Markdown/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# Markdown is a markup format; no installation required. +exit 0 diff --git a/@ether/library/Language/Markdown/repl.sh b/@ether/library/Language/Markdown/repl.sh new file mode 100755 index 00000000..1422ae16 --- /dev/null +++ b/@ether/library/Language/Markdown/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Markdown does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Markdown/run.sh b/@ether/library/Language/Markdown/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/Markdown/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/MarkovJunior/check.sh b/@ether/library/Language/MarkovJunior/check.sh new file mode 100755 index 00000000..0b062a05 --- /dev/null +++ b/@ether/library/Language/MarkovJunior/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mxgmn/MarkovJunior" +[[ -d "$REPO_DIR" ]] && command -v dotnet >/dev/null 2>&1 diff --git a/@ether/library/Language/MarkovJunior/install.sh b/@ether/library/Language/MarkovJunior/install.sh new file mode 100755 index 00000000..7055ebfb --- /dev/null +++ b/@ether/library/Language/MarkovJunior/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +# MarkovJunior - https://github.com/mxgmn/MarkovJunior +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mxgmn/MarkovJunior" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/mxgmn/MarkovJunior.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v dotnet >/dev/null 2>&1 || { echo ".NET SDK required." >&2; exit 1; } +dotnet build -c Release diff --git a/@ether/library/Language/MarkovJunior/repl.sh b/@ether/library/Language/MarkovJunior/repl.sh new file mode 100755 index 00000000..819cb5e8 --- /dev/null +++ b/@ether/library/Language/MarkovJunior/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "MarkovJunior does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/MarkovJunior/run.sh b/@ether/library/Language/MarkovJunior/run.sh new file mode 100755 index 00000000..7c8f4e72 --- /dev/null +++ b/@ether/library/Language/MarkovJunior/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mxgmn/MarkovJunior" +cp "$1" "$REPO_DIR/resources/" 2>/dev/null || true +cd "$REPO_DIR" && dotnet run -c Release diff --git a/@ether/library/Language/Marlowe/check.sh b/@ether/library/Language/Marlowe/check.sh new file mode 100755 index 00000000..a4669f0f --- /dev/null +++ b/@ether/library/Language/Marlowe/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v marlowe-cli >/dev/null 2>&1 diff --git a/@ether/library/Language/Marlowe/install.sh b/@ether/library/Language/Marlowe/install.sh new file mode 100755 index 00000000..a6fc6943 --- /dev/null +++ b/@ether/library/Language/Marlowe/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +# Marlowe: Cardano financial contract DSL - https://marlowe.iohk.io/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/input-output-hk/marlowe-cardano" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/input-output-hk/marlowe-cardano.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cabal build all + exit 0 +fi +# Marlowe requires building from source with GHC/Cabal +if ! command -v ghc >/dev/null 2>&1 || ! command -v cabal >/dev/null 2>&1; then + echo "GHC and Cabal are required. Install via ghcup:" >&2 + echo " curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh" >&2 + exit 1 +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/input-output-hk/marlowe-cardano" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/input-output-hk/marlowe-cardano.git "$REPO_DIR" +fi +cd "$REPO_DIR" && cabal build all diff --git a/@ether/library/Language/Marlowe/packages.sh b/@ether/library/Language/Marlowe/packages.sh new file mode 100755 index 00000000..e4cc0e2f --- /dev/null +++ b/@ether/library/Language/Marlowe/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Marlowe does not have a package manager." +echo "Marlowe Playground: https://play.marlowe.iohk.io" diff --git a/@ether/library/Language/Marlowe/repl.sh b/@ether/library/Language/Marlowe/repl.sh new file mode 100755 index 00000000..527e63c9 --- /dev/null +++ b/@ether/library/Language/Marlowe/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Use Marlowe Playground at play.marlowe.iohk.io" >&2 +exit 1 diff --git a/@ether/library/Language/Marlowe/run.sh b/@ether/library/Language/Marlowe/run.sh new file mode 100755 index 00000000..6066e14a --- /dev/null +++ b/@ether/library/Language/Marlowe/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Marlowe runs within the Cardano ecosystem. Use marlowe-cli or Marlowe Playground." >&2 +exit 1 diff --git a/@ether/library/Language/MathJax/check.sh b/@ether/library/Language/MathJax/check.sh new file mode 100755 index 00000000..db9ca34a --- /dev/null +++ b/@ether/library/Language/MathJax/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +node -e "require('mathjax')" 2>/dev/null diff --git a/@ether/library/Language/MathJax/install.sh b/@ether/library/Language/MathJax/install.sh new file mode 100755 index 00000000..ca1960d8 --- /dev/null +++ b/@ether/library/Language/MathJax/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# MathJax - https://www.mathjax.org/ +npm install -g mathjax diff --git a/@ether/library/Language/MathJax/repl.sh b/@ether/library/Language/MathJax/repl.sh new file mode 100755 index 00000000..de4f1a38 --- /dev/null +++ b/@ether/library/Language/MathJax/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec node -e "const MathJax = require('mathjax'); const repl = require('repl'); repl.start('mathjax> ')" diff --git a/@ether/library/Language/MathJax/run.sh b/@ether/library/Language/MathJax/run.sh new file mode 100755 index 00000000..f082fff1 --- /dev/null +++ b/@ether/library/Language/MathJax/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec node "$1" diff --git a/@ether/library/Language/MathScheme/check.sh b/@ether/library/Language/MathScheme/check.sh new file mode 100755 index 00000000..60fd53eb --- /dev/null +++ b/@ether/library/Language/MathScheme/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/JacquesCarette/MathScheme" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/MathScheme/install.sh b/@ether/library/Language/MathScheme/install.sh new file mode 100755 index 00000000..b96da06b --- /dev/null +++ b/@ether/library/Language/MathScheme/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# MathScheme - https://github.com/JacquesCarette/MathScheme +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/JacquesCarette/MathScheme" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/JacquesCarette/MathScheme.git "$REPO_DIR" +fi +echo "MathScheme source cloned to: $REPO_DIR" +echo "See the repository README for build instructions." diff --git a/@ether/library/Language/MathScheme/repl.sh b/@ether/library/Language/MathScheme/repl.sh new file mode 100755 index 00000000..f7f6bc60 --- /dev/null +++ b/@ether/library/Language/MathScheme/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "MathScheme does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/MathScheme/run.sh b/@ether/library/Language/MathScheme/run.sh new file mode 100755 index 00000000..6532b66f --- /dev/null +++ b/@ether/library/Language/MathScheme/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "MathScheme is a research framework. See the repository for usage." >&2 +exit 1 diff --git a/@ether/library/Language/Mathematics/check.sh b/@ether/library/Language/Mathematics/check.sh new file mode 100755 index 00000000..a2ae9962 --- /dev/null +++ b/@ether/library/Language/Mathematics/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Mathematics is a conceptual language; always available. +exit 0 diff --git a/@ether/library/Language/Mathematics/install.sh b/@ether/library/Language/Mathematics/install.sh new file mode 100755 index 00000000..da4c5512 --- /dev/null +++ b/@ether/library/Language/Mathematics/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# Mathematics is a conceptual/notation language; no installation required. +exit 0 diff --git a/@ether/library/Language/Mathematics/repl.sh b/@ether/library/Language/Mathematics/repl.sh new file mode 100755 index 00000000..0bb142b7 --- /dev/null +++ b/@ether/library/Language/Mathematics/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Mathematics does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Mathematics/run.sh b/@ether/library/Language/Mathematics/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/Mathematics/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/Matita/check.sh b/@ether/library/Language/Matita/check.sh new file mode 100755 index 00000000..1ff4e80b --- /dev/null +++ b/@ether/library/Language/Matita/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v matitac >/dev/null 2>&1 diff --git a/@ether/library/Language/Matita/install.sh b/@ether/library/Language/Matita/install.sh new file mode 100755 index 00000000..aa1215df --- /dev/null +++ b/@ether/library/Language/Matita/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Matita - https://github.com/LPCIC/matita +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/LPCIC/matita" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/LPCIC/matita.git "$REPO_DIR" + fi + cd "$REPO_DIR" + opam install . --deps-only -y + ./configure && make + sudo make install + exit 0 +fi +command -v opam >/dev/null 2>&1 || { echo "opam required. Install OCaml/opam first." >&2; exit 1; } +opam install matita -y diff --git a/@ether/library/Language/Matita/repl.sh b/@ether/library/Language/Matita/repl.sh new file mode 100755 index 00000000..62c0e9d5 --- /dev/null +++ b/@ether/library/Language/Matita/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Matita does not have a command-line REPL. Use the matita GUI." >&2 +exit 1 diff --git a/@ether/library/Language/Matita/run.sh b/@ether/library/Language/Matita/run.sh new file mode 100755 index 00000000..b468fe5f --- /dev/null +++ b/@ether/library/Language/Matita/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec matitac "$1" diff --git a/@ether/library/Language/Maude/check.sh b/@ether/library/Language/Maude/check.sh new file mode 100755 index 00000000..8e654e4e --- /dev/null +++ b/@ether/library/Language/Maude/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v maude >/dev/null 2>&1 diff --git a/@ether/library/Language/Maude/install.sh b/@ether/library/Language/Maude/install.sh new file mode 100755 index 00000000..23214892 --- /dev/null +++ b/@ether/library/Language/Maude/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +# Maude - http://maude.cs.illinois.edu/ +# https://github.com/SRI-CSL/Maude +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/SRI-CSL/Maude" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/SRI-CSL/Maude.git "$REPO_DIR" + fi + cd "$REPO_DIR" + autoreconf -i + ./configure && make -j"$(nproc)" + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install maude +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y maude +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm maude +else + echo "Download binaries from: http://maude.cs.illinois.edu/w/index.php/Maude_download_and_installation" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Maude/repl.sh b/@ether/library/Language/Maude/repl.sh new file mode 100755 index 00000000..a9167717 --- /dev/null +++ b/@ether/library/Language/Maude/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec maude diff --git a/@ether/library/Language/Maude/run.sh b/@ether/library/Language/Maude/run.sh new file mode 100755 index 00000000..8cb3dca9 --- /dev/null +++ b/@ether/library/Language/Maude/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec maude "$1" diff --git a/@ether/library/Language/Maxima/check.sh b/@ether/library/Language/Maxima/check.sh new file mode 100755 index 00000000..c48bd2ff --- /dev/null +++ b/@ether/library/Language/Maxima/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v maxima >/dev/null 2>&1 diff --git a/@ether/library/Language/Maxima/install.sh b/@ether/library/Language/Maxima/install.sh new file mode 100755 index 00000000..4505622b --- /dev/null +++ b/@ether/library/Language/Maxima/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Maxima - https://maxima.sourceforge.io/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install maxima +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y maxima +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y maxima +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm maxima +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Maxima/repl.sh b/@ether/library/Language/Maxima/repl.sh new file mode 100755 index 00000000..5ef74153 --- /dev/null +++ b/@ether/library/Language/Maxima/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec maxima diff --git a/@ether/library/Language/Maxima/run.sh b/@ether/library/Language/Maxima/run.sh new file mode 100755 index 00000000..9e4b1477 --- /dev/null +++ b/@ether/library/Language/Maxima/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec maxima -b "$1" diff --git a/@ether/library/Language/Mercury/check.sh b/@ether/library/Language/Mercury/check.sh new file mode 100755 index 00000000..df616ee9 --- /dev/null +++ b/@ether/library/Language/Mercury/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v mmc >/dev/null 2>&1 diff --git a/@ether/library/Language/Mercury/install.sh b/@ether/library/Language/Mercury/install.sh new file mode 100755 index 00000000..ea0a1264 --- /dev/null +++ b/@ether/library/Language/Mercury/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail +# Mercury - https://www.mercurylang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Mercury-Language/mercury" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Mercury-Language/mercury.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./configure && make PARALLEL=-j"$(nproc)" + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install mercury +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y mercury +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y mercury +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm mercury +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/Mercury/repl.sh b/@ether/library/Language/Mercury/repl.sh new file mode 100755 index 00000000..bf5c63cf --- /dev/null +++ b/@ether/library/Language/Mercury/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Mercury does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Mercury/run.sh b/@ether/library/Language/Mercury/run.sh new file mode 100755 index 00000000..7ba9d88b --- /dev/null +++ b/@ether/library/Language/Mercury/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +base="$(basename "$file" .m)" +dir="$(dirname "$file")" +cd "$dir" && mmc --make "$base" && ./"$base" diff --git a/@ether/library/Language/Mermaid/check.sh b/@ether/library/Language/Mermaid/check.sh new file mode 100755 index 00000000..ad8b2d52 --- /dev/null +++ b/@ether/library/Language/Mermaid/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v mmdc >/dev/null 2>&1 diff --git a/@ether/library/Language/Mermaid/install.sh b/@ether/library/Language/Mermaid/install.sh new file mode 100755 index 00000000..dd494112 --- /dev/null +++ b/@ether/library/Language/Mermaid/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# Mermaid - https://mermaid.js.org/ +npm install -g @mermaid-js/mermaid-cli diff --git a/@ether/library/Language/Mermaid/repl.sh b/@ether/library/Language/Mermaid/repl.sh new file mode 100755 index 00000000..61dadd1e --- /dev/null +++ b/@ether/library/Language/Mermaid/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Mermaid does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Mermaid/run.sh b/@ether/library/Language/Mermaid/run.sh new file mode 100755 index 00000000..26e47a2a --- /dev/null +++ b/@ether/library/Language/Mermaid/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec mmdc -i "$1" -o "${1%.mmd}.svg" diff --git a/@ether/library/Language/Meson/check.sh b/@ether/library/Language/Meson/check.sh new file mode 100755 index 00000000..966ed4e7 --- /dev/null +++ b/@ether/library/Language/Meson/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v meson >/dev/null 2>&1 diff --git a/@ether/library/Language/Meson/install.sh b/@ether/library/Language/Meson/install.sh new file mode 100755 index 00000000..b2d0a279 --- /dev/null +++ b/@ether/library/Language/Meson/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Meson build system +if [[ "$(uname)" == "Darwin" ]]; then + brew install meson +elif command -v pip3 >/dev/null 2>&1; then + pip3 install meson +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y meson +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y meson +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm meson +else + echo "Unsupported package manager. Install via pip: pip3 install meson" >&2; exit 1 +fi diff --git a/@ether/library/Language/Meson/packages.sh b/@ether/library/Language/Meson/packages.sh new file mode 100755 index 00000000..40c22c9f --- /dev/null +++ b/@ether/library/Language/Meson/packages.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://mesonbuild.com/Wrapdb-projects.html" + +usage() { + echo "Meson Package Manager (WrapDB)" + echo "" + echo "Registry: $REGISTRY" + echo "" + echo "Usage: packages.sh [args]" + echo "" + echo "Commands:" + echo " search Search for wraps" + echo " info Show wrap information" + echo " install Install a wrap" +} + +cmd_search() { + if command -v meson &>/dev/null; then + meson wrap search "$@" + else + echo "meson not found. Search online:" + echo " $REGISTRY" + fi +} + +cmd_info() { + local wrap="$1" + if command -v meson &>/dev/null; then + meson wrap info "$wrap" + else + echo "meson not found. View online:" + echo " $REGISTRY" + fi +} + +cmd_install() { + local wrap="$1" + if command -v meson &>/dev/null; then + meson wrap install "$wrap" + else + echo "meson not found. Install Meson first:" + echo " pip install meson" + echo " https://mesonbuild.com/Getting-meson.html" + fi +} + +case "${1:-}" in + search) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh search "; exit 1; } + cmd_search "$@" + ;; + info) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh info "; exit 1; } + cmd_info "$1" + ;; + install) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh install "; exit 1; } + cmd_install "$1" + ;; + *) + usage + ;; +esac diff --git a/@ether/library/Language/Meson/repl.sh b/@ether/library/Language/Meson/repl.sh new file mode 100755 index 00000000..ce3a69ef --- /dev/null +++ b/@ether/library/Language/Meson/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Meson does not have an interactive REPL." diff --git a/@ether/library/Language/Meson/run.sh b/@ether/library/Language/Meson/run.sh new file mode 100755 index 00000000..7f2731b0 --- /dev/null +++ b/@ether/library/Language/Meson/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec meson "$@" diff --git a/@ether/library/Language/MessagePack/check.sh b/@ether/library/Language/MessagePack/check.sh new file mode 100755 index 00000000..fdf85e7a --- /dev/null +++ b/@ether/library/Language/MessagePack/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# MessagePack is a data format; always available. +exit 0 diff --git a/@ether/library/Language/MessagePack/install.sh b/@ether/library/Language/MessagePack/install.sh new file mode 100755 index 00000000..d487cea8 --- /dev/null +++ b/@ether/library/Language/MessagePack/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# MessagePack is a binary serialization format; no installation required. +# Libraries exist for many languages. See: https://msgpack.org/ +exit 0 diff --git a/@ether/library/Language/MessagePack/repl.sh b/@ether/library/Language/MessagePack/repl.sh new file mode 100755 index 00000000..25c7d678 --- /dev/null +++ b/@ether/library/Language/MessagePack/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "MessagePack does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/MessagePack/run.sh b/@ether/library/Language/MessagePack/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/MessagePack/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/Metamath/check.sh b/@ether/library/Language/Metamath/check.sh new file mode 100755 index 00000000..cf3ff20f --- /dev/null +++ b/@ether/library/Language/Metamath/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v metamath >/dev/null 2>&1 diff --git a/@ether/library/Language/Metamath/install.sh b/@ether/library/Language/Metamath/install.sh new file mode 100755 index 00000000..ea5d7158 --- /dev/null +++ b/@ether/library/Language/Metamath/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Metamath - https://github.com/metamath/metamath-exe +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/metamath/metamath-exe" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/metamath/metamath-exe.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if [[ -f CMakeLists.txt ]]; then + mkdir -p build && cd build && cmake .. && make -j"$(nproc)" + sudo make install +elif [[ -f Makefile ]]; then + make -j"$(nproc)" + sudo cp metamath /usr/local/bin/ +else + gcc -O2 -o metamath src/*.c + sudo cp metamath /usr/local/bin/ +fi diff --git a/@ether/library/Language/Metamath/repl.sh b/@ether/library/Language/Metamath/repl.sh new file mode 100755 index 00000000..ef8e87f5 --- /dev/null +++ b/@ether/library/Language/Metamath/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec metamath diff --git a/@ether/library/Language/Metamath/run.sh b/@ether/library/Language/Metamath/run.sh new file mode 100755 index 00000000..e08b32af --- /dev/null +++ b/@ether/library/Language/Metamath/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec metamath "read '$1'" "verify proof *" "exit" diff --git a/@ether/library/Language/Michelson/check.sh b/@ether/library/Language/Michelson/check.sh new file mode 100755 index 00000000..b6da33ca --- /dev/null +++ b/@ether/library/Language/Michelson/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v octez-client >/dev/null 2>&1 || command -v tezos-client >/dev/null 2>&1 diff --git a/@ether/library/Language/Michelson/install.sh b/@ether/library/Language/Michelson/install.sh new file mode 100755 index 00000000..85abe7e9 --- /dev/null +++ b/@ether/library/Language/Michelson/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +# Michelson - Tezos smart contract language +# https://tezos.gitlab.io/active/michelson.html +# Installed via the Octez client (tezos-client) +if [[ "$(uname)" == "Darwin" ]]; then + brew install tezos +elif command -v apt-get >/dev/null 2>&1; then + sudo add-apt-repository -y ppa:serokell/tezos 2>/dev/null || true + sudo apt-get update && sudo apt-get install -y tezos-client +elif command -v dnf >/dev/null 2>&1; then + echo "Install Octez from: https://tezos.gitlab.io/introduction/howtoget.html" >&2 + exit 1 +elif command -v pacman >/dev/null 2>&1; then + echo "Install Octez from: https://tezos.gitlab.io/introduction/howtoget.html" >&2 + exit 1 +else + echo "Unsupported platform. See: https://tezos.gitlab.io/introduction/howtoget.html" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Michelson/repl.sh b/@ether/library/Language/Michelson/repl.sh new file mode 100755 index 00000000..8b0fa371 --- /dev/null +++ b/@ether/library/Language/Michelson/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Michelson does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Michelson/run.sh b/@ether/library/Language/Michelson/run.sh new file mode 100755 index 00000000..7c321427 --- /dev/null +++ b/@ether/library/Language/Michelson/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +CLIENT="octez-client" +command -v "$CLIENT" >/dev/null 2>&1 || CLIENT="tezos-client" +exec "$CLIENT" typecheck script "$1" diff --git a/@ether/library/Language/MiniSat/check.sh b/@ether/library/Language/MiniSat/check.sh new file mode 100755 index 00000000..fc42552f --- /dev/null +++ b/@ether/library/Language/MiniSat/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v minisat >/dev/null 2>&1 diff --git a/@ether/library/Language/MiniSat/install.sh b/@ether/library/Language/MiniSat/install.sh new file mode 100755 index 00000000..9df9733d --- /dev/null +++ b/@ether/library/Language/MiniSat/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +# MiniSat - http://minisat.se/ +# https://github.com/niklasso/minisat +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/niklasso/minisat" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/niklasso/minisat.git "$REPO_DIR" + fi + cd "$REPO_DIR" + make -j"$(nproc)" + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install minisat +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y minisat +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y minisat2 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm minisat +else + echo "Unsupported package manager. Use FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/MiniSat/repl.sh b/@ether/library/Language/MiniSat/repl.sh new file mode 100755 index 00000000..fb8a7718 --- /dev/null +++ b/@ether/library/Language/MiniSat/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "MiniSat does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/MiniSat/run.sh b/@ether/library/Language/MiniSat/run.sh new file mode 100755 index 00000000..78861526 --- /dev/null +++ b/@ether/library/Language/MiniSat/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec minisat "$1" diff --git a/@ether/library/Language/MiniZinc/check.sh b/@ether/library/Language/MiniZinc/check.sh new file mode 100755 index 00000000..5cee91da --- /dev/null +++ b/@ether/library/Language/MiniZinc/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v minizinc >/dev/null 2>&1 diff --git a/@ether/library/Language/MiniZinc/install.sh b/@ether/library/Language/MiniZinc/install.sh new file mode 100755 index 00000000..f5df6d40 --- /dev/null +++ b/@ether/library/Language/MiniZinc/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# MiniZinc - https://www.minizinc.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/MiniZinc/libminizinc" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/MiniZinc/libminizinc.git "$REPO_DIR" + fi + cd "$REPO_DIR" + mkdir -p build && cd build + cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build . -j"$(nproc)" + sudo cmake --install . + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install minizinc +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y minizinc +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm minizinc +else + echo "Download from: https://www.minizinc.org/software.html" >&2; exit 1 +fi diff --git a/@ether/library/Language/MiniZinc/repl.sh b/@ether/library/Language/MiniZinc/repl.sh new file mode 100755 index 00000000..4429d09a --- /dev/null +++ b/@ether/library/Language/MiniZinc/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "MiniZinc does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/MiniZinc/run.sh b/@ether/library/Language/MiniZinc/run.sh new file mode 100755 index 00000000..9296cfec --- /dev/null +++ b/@ether/library/Language/MiniZinc/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec minizinc "$1" diff --git a/@ether/library/Language/Mint/check.sh b/@ether/library/Language/Mint/check.sh new file mode 100755 index 00000000..e0a62902 --- /dev/null +++ b/@ether/library/Language/Mint/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v mint >/dev/null 2>&1 diff --git a/@ether/library/Language/Mint/install.sh b/@ether/library/Language/Mint/install.sh new file mode 100755 index 00000000..3296d419 --- /dev/null +++ b/@ether/library/Language/Mint/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +# Mint - https://mint-lang.com/ +# https://github.com/mint-lang/mint +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mint-lang/mint" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/mint-lang/mint.git "$REPO_DIR" + fi + cd "$REPO_DIR" + command -v shards >/dev/null 2>&1 || { echo "Crystal language required." >&2; exit 1; } + shards install && crystal build src/mint.cr --release -o mint + sudo cp mint /usr/local/bin/ + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew tap aspect-build/aspect && brew install mint-lang +else + # Install from GitHub releases + curl -sSL https://mint-lang.com/install.sh | bash +fi diff --git a/@ether/library/Language/Mint/repl.sh b/@ether/library/Language/Mint/repl.sh new file mode 100755 index 00000000..f3d3b105 --- /dev/null +++ b/@ether/library/Language/Mint/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Mint does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Mint/run.sh b/@ether/library/Language/Mint/run.sh new file mode 100755 index 00000000..3bc06061 --- /dev/null +++ b/@ether/library/Language/Mint/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec mint build "$1" diff --git a/@ether/library/Language/Minuska/check.sh b/@ether/library/Language/Minuska/check.sh new file mode 100755 index 00000000..de0d9f61 --- /dev/null +++ b/@ether/library/Language/Minuska/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v minuska >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/h0nzZik/minuska" + [[ -d "$REPO_DIR" ]] +} diff --git a/@ether/library/Language/Minuska/install.sh b/@ether/library/Language/Minuska/install.sh new file mode 100755 index 00000000..807d93d2 --- /dev/null +++ b/@ether/library/Language/Minuska/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Minuska - https://github.com/h0nzZik/minuska +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/h0nzZik/minuska" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/h0nzZik/minuska.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v opam >/dev/null 2>&1 || { echo "opam required." >&2; exit 1; } +opam install . --deps-only -y +make diff --git a/@ether/library/Language/Minuska/repl.sh b/@ether/library/Language/Minuska/repl.sh new file mode 100755 index 00000000..7f82df15 --- /dev/null +++ b/@ether/library/Language/Minuska/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Minuska does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Minuska/run.sh b/@ether/library/Language/Minuska/run.sh new file mode 100755 index 00000000..604ca103 --- /dev/null +++ b/@ether/library/Language/Minuska/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v minuska >/dev/null 2>&1; then + exec minuska "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/h0nzZik/minuska" + cd "$REPO_DIR" && exec make run FILE="$1" +fi diff --git a/@ether/library/Language/Mizar/check.sh b/@ether/library/Language/Mizar/check.sh new file mode 100755 index 00000000..8a993144 --- /dev/null +++ b/@ether/library/Language/Mizar/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v mizf >/dev/null 2>&1 || command -v verifier >/dev/null 2>&1 diff --git a/@ether/library/Language/Mizar/install.sh b/@ether/library/Language/Mizar/install.sh new file mode 100755 index 00000000..7a6613ff --- /dev/null +++ b/@ether/library/Language/Mizar/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Mizar - https://mizar.uwb.edu.pl/ +# Download from official site +echo "Downloading Mizar from official site..." +MIZAR_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/mizar" +mkdir -p "$MIZAR_DIR" +if [[ "$(uname)" == "Linux" ]]; then + curl -sSL "https://mizar.uwb.edu.pl/~softadm/pub/system/x86_64-linux/mizar-latest-linux.tar" -o "$MIZAR_DIR/mizar.tar" + cd "$MIZAR_DIR" && tar xf mizar.tar + sudo cp bin/* /usr/local/bin/ 2>/dev/null || cp bin/* "$HOME/.local/bin/" +elif [[ "$(uname)" == "Darwin" ]]; then + echo "Mizar does not provide official macOS binaries." + echo "See: https://mizar.uwb.edu.pl/" + exit 1 +fi diff --git a/@ether/library/Language/Mizar/repl.sh b/@ether/library/Language/Mizar/repl.sh new file mode 100755 index 00000000..ff151616 --- /dev/null +++ b/@ether/library/Language/Mizar/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Mizar does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Mizar/run.sh b/@ether/library/Language/Mizar/run.sh new file mode 100755 index 00000000..00e954f4 --- /dev/null +++ b/@ether/library/Language/Mizar/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v mizf >/dev/null 2>&1; then + exec mizf "$1" +else + exec verifier "$1" +fi diff --git a/@ether/library/Language/Mojo/check.sh b/@ether/library/Language/Mojo/check.sh new file mode 100755 index 00000000..62c82525 --- /dev/null +++ b/@ether/library/Language/Mojo/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v mojo >/dev/null 2>&1 diff --git a/@ether/library/Language/Mojo/install.sh b/@ether/library/Language/Mojo/install.sh new file mode 100755 index 00000000..5f0443c7 --- /dev/null +++ b/@ether/library/Language/Mojo/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Mojo - https://docs.modular.com/mojo/manual/get-started +# Official install via modular CLI +if [[ "$(uname)" == "Darwin" ]]; then + brew install modular + modular install mojo +elif [[ "$(uname)" == "Linux" ]]; then + curl -ssL https://magic.modular.com | bash + export PATH="$HOME/.modular/bin:$PATH" + magic install mojo +else + echo "Unsupported platform." >&2; exit 1 +fi diff --git a/@ether/library/Language/Mojo/repl.sh b/@ether/library/Language/Mojo/repl.sh new file mode 100755 index 00000000..cd6d5852 --- /dev/null +++ b/@ether/library/Language/Mojo/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec mojo diff --git a/@ether/library/Language/Mojo/run.sh b/@ether/library/Language/Mojo/run.sh new file mode 100755 index 00000000..0d839a84 --- /dev/null +++ b/@ether/library/Language/Mojo/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec mojo run "$1" diff --git a/@ether/library/Language/MonoidalComputer/check.sh b/@ether/library/Language/MonoidalComputer/check.sh new file mode 100755 index 00000000..fcd32619 --- /dev/null +++ b/@ether/library/Language/MonoidalComputer/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Monoidal Computer is a theoretical concept; always available. +exit 0 diff --git a/@ether/library/Language/MonoidalComputer/install.sh b/@ether/library/Language/MonoidalComputer/install.sh new file mode 100755 index 00000000..75890413 --- /dev/null +++ b/@ether/library/Language/MonoidalComputer/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +# Monoidal Computer - theoretical framework +# https://arxiv.org/abs/1208.5205 +# This is a theoretical/mathematical concept, not an executable tool. +exit 0 diff --git a/@ether/library/Language/MonoidalComputer/repl.sh b/@ether/library/Language/MonoidalComputer/repl.sh new file mode 100755 index 00000000..9e3e762e --- /dev/null +++ b/@ether/library/Language/MonoidalComputer/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Monoidal Computer does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/MonoidalComputer/run.sh b/@ether/library/Language/MonoidalComputer/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/MonoidalComputer/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/MoonBit/check.sh b/@ether/library/Language/MoonBit/check.sh new file mode 100755 index 00000000..88326e45 --- /dev/null +++ b/@ether/library/Language/MoonBit/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v moon >/dev/null 2>&1 diff --git a/@ether/library/Language/MoonBit/install.sh b/@ether/library/Language/MoonBit/install.sh new file mode 100755 index 00000000..4b8ab76d --- /dev/null +++ b/@ether/library/Language/MoonBit/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# MoonBit - https://www.moonbitlang.com/ +# Official installer +curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash diff --git a/@ether/library/Language/MoonBit/repl.sh b/@ether/library/Language/MoonBit/repl.sh new file mode 100755 index 00000000..069a7a55 --- /dev/null +++ b/@ether/library/Language/MoonBit/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "MoonBit does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/MoonBit/run.sh b/@ether/library/Language/MoonBit/run.sh new file mode 100755 index 00000000..b36cb2a4 --- /dev/null +++ b/@ether/library/Language/MoonBit/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec moon run "$1" diff --git a/@ether/library/Language/Motoko/check.sh b/@ether/library/Language/Motoko/check.sh new file mode 100755 index 00000000..4221aca3 --- /dev/null +++ b/@ether/library/Language/Motoko/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v moc >/dev/null 2>&1 || command -v dfx >/dev/null 2>&1 diff --git a/@ether/library/Language/Motoko/install.sh b/@ether/library/Language/Motoko/install.sh new file mode 100755 index 00000000..6f2c764a --- /dev/null +++ b/@ether/library/Language/Motoko/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Motoko: Internet Computer smart contract language - https://internetcomputer.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/dfinity/motoko" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/dfinity/motoko.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make + exit 0 +fi +# Install dfx (DFINITY Canister SDK) which includes moc (Motoko compiler) +sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)" diff --git a/@ether/library/Language/Motoko/packages.sh b/@ether/library/Language/Motoko/packages.sh new file mode 100755 index 00000000..d4fc075d --- /dev/null +++ b/@ether/library/Language/Motoko/packages.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Motoko" +REGISTRIES=( + "Mops: https://mops.one" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v mops &>/dev/null; then + mops search "$@" + else + echo "Visit: https://mops.one/?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://mops.one/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + if command -v mops &>/dev/null; then + mops add "$1" + else + echo "mops not found. Install it first:" + echo " npm install -g ic-mops" + echo "" + echo "Then run: mops add $1" + fi + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Motoko/repl.sh b/@ether/library/Language/Motoko/repl.sh new file mode 100755 index 00000000..c184cff4 --- /dev/null +++ b/@ether/library/Language/Motoko/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Use dfx canister call for interactive testing." >&2 +exit 1 diff --git a/@ether/library/Language/Motoko/run.sh b/@ether/library/Language/Motoko/run.sh new file mode 100755 index 00000000..fbcf24ab --- /dev/null +++ b/@ether/library/Language/Motoko/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v moc >/dev/null 2>&1; then + exec moc "$@" +else + exec dfx build "$@" +fi diff --git a/@ether/library/Language/Move/check.sh b/@ether/library/Language/Move/check.sh new file mode 100755 index 00000000..c470414c --- /dev/null +++ b/@ether/library/Language/Move/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v move >/dev/null 2>&1 diff --git a/@ether/library/Language/Move/install.sh b/@ether/library/Language/Move/install.sh new file mode 100755 index 00000000..b1cbb351 --- /dev/null +++ b/@ether/library/Language/Move/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +# Move - https://github.com/move-language/move +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/move-language/move" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/move-language/move.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v cargo >/dev/null 2>&1 || { echo "Rust/Cargo required." >&2; exit 1; } +cargo install --path language/tools/move-cli diff --git a/@ether/library/Language/Move/repl.sh b/@ether/library/Language/Move/repl.sh new file mode 100755 index 00000000..e6a68b9a --- /dev/null +++ b/@ether/library/Language/Move/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Move does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Move/run.sh b/@ether/library/Language/Move/run.sh new file mode 100755 index 00000000..74d6c842 --- /dev/null +++ b/@ether/library/Language/Move/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec move run "$1" diff --git a/@ether/library/Language/MultiVerse/check.sh b/@ether/library/Language/MultiVerse/check.sh new file mode 100755 index 00000000..04d7166f --- /dev/null +++ b/@ether/library/Language/MultiVerse/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import multiverse" >/dev/null 2>&1 diff --git a/@ether/library/Language/MultiVerse/install.sh b/@ether/library/Language/MultiVerse/install.sh new file mode 100755 index 00000000..94fa1ee9 --- /dev/null +++ b/@ether/library/Language/MultiVerse/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing MultiVerse from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/babylonhealth/multiverse" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/babylonhealth/multiverse.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install . + exit 0 +fi +pip install multiverse diff --git a/@ether/library/Language/MultiVerse/repl.sh b/@ether/library/Language/MultiVerse/repl.sh new file mode 100755 index 00000000..6de9b748 --- /dev/null +++ b/@ether/library/Language/MultiVerse/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import multiverse; help(multiverse)" 2>/dev/null || exec python3 diff --git a/@ether/library/Language/MultiVerse/run.sh b/@ether/library/Language/MultiVerse/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/MultiVerse/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/NASM/check.sh b/@ether/library/Language/NASM/check.sh new file mode 100755 index 00000000..ed4aa9c7 --- /dev/null +++ b/@ether/library/Language/NASM/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nasm >/dev/null 2>&1 diff --git a/@ether/library/Language/NASM/install.sh b/@ether/library/Language/NASM/install.sh new file mode 100755 index 00000000..0e830b25 --- /dev/null +++ b/@ether/library/Language/NASM/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing NASM from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/netwide-assembler/nasm" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/netwide-assembler/nasm.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./autogen.sh + ./configure --prefix="$HOME/.local" + make -j"$(nproc)" + make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install nasm +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y nasm +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y nasm +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm nasm +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/NASM/repl.sh b/@ether/library/Language/NASM/repl.sh new file mode 100755 index 00000000..4a295e84 --- /dev/null +++ b/@ether/library/Language/NASM/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "NASM is an assembler and does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/NASM/run.sh b/@ether/library/Language/NASM/run.sh new file mode 100755 index 00000000..703c1aa7 --- /dev/null +++ b/@ether/library/Language/NASM/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nasm "$@" diff --git a/@ether/library/Language/NQTHM/check.sh b/@ether/library/Language/NQTHM/check.sh new file mode 100755 index 00000000..9fd6ee65 --- /dev/null +++ b/@ether/library/Language/NQTHM/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nqthm >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/John-Nagle/nqthm" + [[ -d "$REPO_DIR" ]] +} diff --git a/@ether/library/Language/NQTHM/install.sh b/@ether/library/Language/NQTHM/install.sh new file mode 100755 index 00000000..4868d8b8 --- /dev/null +++ b/@ether/library/Language/NQTHM/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing NQTHM from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/John-Nagle/nqthm" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/John-Nagle/nqthm.git "$REPO_DIR" +fi +echo "NQTHM source cloned to $REPO_DIR. Requires a Common Lisp implementation to build." +echo "See $REPO_DIR for build instructions." diff --git a/@ether/library/Language/NQTHM/repl.sh b/@ether/library/Language/NQTHM/repl.sh new file mode 100755 index 00000000..0b2f3e44 --- /dev/null +++ b/@ether/library/Language/NQTHM/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nqthm diff --git a/@ether/library/Language/NQTHM/run.sh b/@ether/library/Language/NQTHM/run.sh new file mode 100755 index 00000000..2b3c0dc1 --- /dev/null +++ b/@ether/library/Language/NQTHM/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nqthm "$@" diff --git a/@ether/library/Language/Narya/check.sh b/@ether/library/Language/Narya/check.sh new file mode 100755 index 00000000..6efd2934 --- /dev/null +++ b/@ether/library/Language/Narya/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v narya >/dev/null 2>&1 diff --git a/@ether/library/Language/Narya/install.sh b/@ether/library/Language/Narya/install.sh new file mode 100755 index 00000000..d466358b --- /dev/null +++ b/@ether/library/Language/Narya/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Narya from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mikeshulman/narya" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/mikeshulman/narya.git "$REPO_DIR" +fi +cd "$REPO_DIR" +opam install . --deps-only -y +dune build +dune install diff --git a/@ether/library/Language/Narya/repl.sh b/@ether/library/Language/Narya/repl.sh new file mode 100755 index 00000000..008f500c --- /dev/null +++ b/@ether/library/Language/Narya/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec narya diff --git a/@ether/library/Language/Narya/run.sh b/@ether/library/Language/Narya/run.sh new file mode 100755 index 00000000..535951b3 --- /dev/null +++ b/@ether/library/Language/Narya/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec narya "$@" diff --git a/@ether/library/Language/Nelua/check.sh b/@ether/library/Language/Nelua/check.sh new file mode 100755 index 00000000..021e4c81 --- /dev/null +++ b/@ether/library/Language/Nelua/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nelua >/dev/null 2>&1 diff --git a/@ether/library/Language/Nelua/install.sh b/@ether/library/Language/Nelua/install.sh new file mode 100755 index 00000000..f8f308ff --- /dev/null +++ b/@ether/library/Language/Nelua/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Nelua from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/edubart/nelua-lang" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/edubart/nelua-lang.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make +sudo make install diff --git a/@ether/library/Language/Nelua/repl.sh b/@ether/library/Language/Nelua/repl.sh new file mode 100755 index 00000000..f304a4c8 --- /dev/null +++ b/@ether/library/Language/Nelua/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Nelua does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Nelua/run.sh b/@ether/library/Language/Nelua/run.sh new file mode 100755 index 00000000..ee877013 --- /dev/null +++ b/@ether/library/Language/Nelua/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nelua "$@" diff --git a/@ether/library/Language/Nickel/check.sh b/@ether/library/Language/Nickel/check.sh new file mode 100755 index 00000000..53806065 --- /dev/null +++ b/@ether/library/Language/Nickel/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nickel >/dev/null 2>&1 diff --git a/@ether/library/Language/Nickel/install.sh b/@ether/library/Language/Nickel/install.sh new file mode 100755 index 00000000..7dd87a69 --- /dev/null +++ b/@ether/library/Language/Nickel/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Nickel from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/tweag/nickel" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/tweag/nickel.git "$REPO_DIR" + fi + cd "$REPO_DIR" + cargo build --release + cp target/release/nickel "$HOME/.local/bin/" + exit 0 +fi +if command -v nix >/dev/null 2>&1; then + nix profile install nixpkgs#nickel +elif [[ "$(uname)" == "Darwin" ]]; then + brew install nickel +elif command -v cargo >/dev/null 2>&1; then + cargo install nickel-lang-cli +else + echo "Install via nix, brew, or cargo. Or use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Nickel/repl.sh b/@ether/library/Language/Nickel/repl.sh new file mode 100755 index 00000000..b60ca825 --- /dev/null +++ b/@ether/library/Language/Nickel/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nickel repl diff --git a/@ether/library/Language/Nickel/run.sh b/@ether/library/Language/Nickel/run.sh new file mode 100755 index 00000000..a1d8a4fc --- /dev/null +++ b/@ether/library/Language/Nickel/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nickel eval "$@" diff --git a/@ether/library/Language/Nim/check.sh b/@ether/library/Language/Nim/check.sh new file mode 100755 index 00000000..2806b743 --- /dev/null +++ b/@ether/library/Language/Nim/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v nim >/dev/null 2>&1 diff --git a/@ether/library/Language/Nim/install.sh b/@ether/library/Language/Nim/install.sh new file mode 100755 index 00000000..81fbaaef --- /dev/null +++ b/@ether/library/Language/Nim/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official method: choosenim - https://nim-lang.org/install_unix.html +if [[ "$(uname)" == "Darwin" ]]; then + brew install nim +else + curl https://nim-lang.org/choosenim/init.sh -sSf | sh -s -- -y +fi diff --git a/@ether/library/Language/Nim/packages.sh b/@ether/library/Language/Nim/packages.sh new file mode 100755 index 00000000..29970ada --- /dev/null +++ b/@ether/library/Language/Nim/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Nim" +REGISTRIES=( + "Nimble Directory: https://nimble.directory" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v nimble &>/dev/null; then + nimble search "$@" + else + echo "Visit: https://nimble.directory/search?query=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v nimble &>/dev/null; then + nimble dump "$1" 2>/dev/null || echo "Visit: https://nimble.directory/pkg/$1" + else + echo "Visit: https://nimble.directory/pkg/$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + nimble install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Nim/repl.sh b/@ether/library/Language/Nim/repl.sh new file mode 100755 index 00000000..1b902d40 --- /dev/null +++ b/@ether/library/Language/Nim/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v nim >/dev/null 2>&1; then + exec nim secret "$@" +else + echo "Nim is not installed." + exit 1 +fi diff --git a/@ether/library/Language/Nim/run.sh b/@ether/library/Language/Nim/run.sh new file mode 100755 index 00000000..aa597f39 --- /dev/null +++ b/@ether/library/Language/Nim/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +nim compile --run "$file" diff --git a/@ether/library/Language/Nit/check.sh b/@ether/library/Language/Nit/check.sh new file mode 100755 index 00000000..81d57f79 --- /dev/null +++ b/@ether/library/Language/Nit/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nitc >/dev/null 2>&1 diff --git a/@ether/library/Language/Nit/install.sh b/@ether/library/Language/Nit/install.sh new file mode 100755 index 00000000..ffd02b81 --- /dev/null +++ b/@ether/library/Language/Nit/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Nit from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/nitlang/nit" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/nitlang/nit.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make +. misc/nit_env.sh diff --git a/@ether/library/Language/Nit/repl.sh b/@ether/library/Language/Nit/repl.sh new file mode 100755 index 00000000..e37e3066 --- /dev/null +++ b/@ether/library/Language/Nit/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nit diff --git a/@ether/library/Language/Nit/run.sh b/@ether/library/Language/Nit/run.sh new file mode 100755 index 00000000..a7cc2395 --- /dev/null +++ b/@ether/library/Language/Nit/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nitc "$@" diff --git a/@ether/library/Language/Nix/check.sh b/@ether/library/Language/Nix/check.sh new file mode 100755 index 00000000..7d2f2258 --- /dev/null +++ b/@ether/library/Language/Nix/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v nix >/dev/null 2>&1 diff --git a/@ether/library/Language/Nix/install.sh b/@ether/library/Language/Nix/install.sh new file mode 100755 index 00000000..8b408eae --- /dev/null +++ b/@ether/library/Language/Nix/install.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v nix >/dev/null 2>&1; then + echo "Nix is already installed." + exit 0 +fi +curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --no-confirm diff --git a/@ether/library/Language/Nix/packages.sh b/@ether/library/Language/Nix/packages.sh new file mode 100755 index 00000000..583080fe --- /dev/null +++ b/@ether/library/Language/Nix/packages.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Nix" +REGISTRIES=( + "Nix Packages: https://search.nixos.org/packages" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v nix &>/dev/null; then + nix search nixpkgs "$@" 2>/dev/null || echo "Visit: https://search.nixos.org/packages?query=$1" + else + echo "Visit: https://search.nixos.org/packages?query=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v nix &>/dev/null; then + nix eval "nixpkgs#$1.meta" --json 2>/dev/null || echo "Visit: https://search.nixos.org/packages?query=$1" + else + echo "Visit: https://search.nixos.org/packages?query=$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + if command -v nix &>/dev/null && nix profile list &>/dev/null; then + nix profile install "nixpkgs#$1" + elif command -v nix-env &>/dev/null; then + nix-env -iA "nixpkgs.$1" + else + echo "Nix is not installed. Visit: https://nixos.org/download.html" + fi + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Nix/repl.sh b/@ether/library/Language/Nix/repl.sh new file mode 100755 index 00000000..c827b834 --- /dev/null +++ b/@ether/library/Language/Nix/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec nix repl diff --git a/@ether/library/Language/Nix/run.sh b/@ether/library/Language/Nix/run.sh new file mode 100755 index 00000000..cc40b7a9 --- /dev/null +++ b/@ether/library/Language/Nix/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec nix eval --file "$@" diff --git a/@ether/library/Language/NodeJS/check.sh b/@ether/library/Language/NodeJS/check.sh new file mode 100755 index 00000000..da83d146 --- /dev/null +++ b/@ether/library/Language/NodeJS/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v node >/dev/null 2>&1 diff --git a/@ether/library/Language/NodeJS/install.sh b/@ether/library/Language/NodeJS/install.sh new file mode 100755 index 00000000..07a7d6db --- /dev/null +++ b/@ether/library/Language/NodeJS/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official install: https://nodejs.org/en/download +if [[ "$(uname)" == "Darwin" ]]; then + brew install node +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm nodejs npm +elif command -v apt-get >/dev/null 2>&1; then + # Default apt nodejs is outdated; use NodeSource LTS repo + curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo bash - + sudo apt-get install -y nodejs +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y nodejs npm +else + # Fallback: fnm (Fast Node Manager) + curl -fsSL https://fnm.vercel.app/install | bash + export PATH="$HOME/.local/share/fnm:$PATH" + eval "$(fnm env)" + fnm install --lts +fi diff --git a/@ether/library/Language/NodeJS/packages.sh b/@ether/library/Language/NodeJS/packages.sh new file mode 100755 index 00000000..02628415 --- /dev/null +++ b/@ether/library/Language/NodeJS/packages.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="NodeJS" +REGISTRIES=( + "npm: https://www.npmjs.com" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + npm search "$@" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + npm info "$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + npm install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/NodeJS/repl.sh b/@ether/library/Language/NodeJS/repl.sh new file mode 100755 index 00000000..f8a0b331 --- /dev/null +++ b/@ether/library/Language/NodeJS/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec node diff --git a/@ether/library/Language/NodeJS/run.sh b/@ether/library/Language/NodeJS/run.sh new file mode 100755 index 00000000..339608e1 --- /dev/null +++ b/@ether/library/Language/NodeJS/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec node "$@" diff --git a/@ether/library/Language/Noir/check.sh b/@ether/library/Language/Noir/check.sh new file mode 100755 index 00000000..a92d5c9c --- /dev/null +++ b/@ether/library/Language/Noir/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v nargo >/dev/null 2>&1 diff --git a/@ether/library/Language/Noir/install.sh b/@ether/library/Language/Noir/install.sh new file mode 100755 index 00000000..4ce61436 --- /dev/null +++ b/@ether/library/Language/Noir/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +# Noir: Aztec zero-knowledge proof language - https://noir-lang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/noir-lang/noir" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/noir-lang/noir.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + exit 0 +fi +# Install noirup (Noir toolchain manager) and then install nargo +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +export PATH="$HOME/.nargo/bin:$PATH" +noirup diff --git a/@ether/library/Language/Noir/packages.sh b/@ether/library/Language/Noir/packages.sh new file mode 100755 index 00000000..b090fce8 --- /dev/null +++ b/@ether/library/Language/Noir/packages.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Noir" +REGISTRIES=( + "GitHub (primary): https://github.com/search?q=noir+lang&type=repositories" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Note: Noir uses Nargo for dependency management. Packages are distributed via GitHub." + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://github.com/search?q=noir+$1&type=repositories" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://github.com/search?q=noir+$1&type=repositories" + echo "Check Nargo.toml in the repository for version and dependency info." + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to Nargo.toml [dependencies]:" + echo " $1 = { tag = \"v0.1.0\", git = \"https://github.com/OWNER/$1\" }" + echo "" + echo "Then run: nargo check" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Noir/repl.sh b/@ether/library/Language/Noir/repl.sh new file mode 100755 index 00000000..38b92335 --- /dev/null +++ b/@ether/library/Language/Noir/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Noir does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Noir/run.sh b/@ether/library/Language/Noir/run.sh new file mode 100755 index 00000000..121d8236 --- /dev/null +++ b/@ether/library/Language/Noir/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nargo compile "$@" diff --git a/@ether/library/Language/NuPRL/check.sh b/@ether/library/Language/NuPRL/check.sh new file mode 100755 index 00000000..49b9878d --- /dev/null +++ b/@ether/library/Language/NuPRL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nuprl >/dev/null 2>&1 diff --git a/@ether/library/Language/NuPRL/install.sh b/@ether/library/Language/NuPRL/install.sh new file mode 100755 index 00000000..91ea2e76 --- /dev/null +++ b/@ether/library/Language/NuPRL/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "NuPRL is an academic proof system from Cornell University." +echo "See https://nuprl-web.cs.cornell.edu/ for installation instructions." +echo "NuPRL typically requires OCaml and specific dependencies from its distribution." +exit 1 diff --git a/@ether/library/Language/NuPRL/repl.sh b/@ether/library/Language/NuPRL/repl.sh new file mode 100755 index 00000000..5ce88cb7 --- /dev/null +++ b/@ether/library/Language/NuPRL/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nuprl diff --git a/@ether/library/Language/NuPRL/run.sh b/@ether/library/Language/NuPRL/run.sh new file mode 100755 index 00000000..02ab4833 --- /dev/null +++ b/@ether/library/Language/NuPRL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nuprl "$@" diff --git a/@ether/library/Language/NumPy/check.sh b/@ether/library/Language/NumPy/check.sh new file mode 100755 index 00000000..3d2547bb --- /dev/null +++ b/@ether/library/Language/NumPy/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import numpy" >/dev/null 2>&1 diff --git a/@ether/library/Language/NumPy/install.sh b/@ether/library/Language/NumPy/install.sh new file mode 100755 index 00000000..534b1846 --- /dev/null +++ b/@ether/library/Language/NumPy/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing NumPy from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/numpy/numpy" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/numpy/numpy.git "$REPO_DIR" + fi + cd "$REPO_DIR" + git submodule update --init + pip install . + exit 0 +fi +pip install numpy diff --git a/@ether/library/Language/NumPy/repl.sh b/@ether/library/Language/NumPy/repl.sh new file mode 100755 index 00000000..3a7204c5 --- /dev/null +++ b/@ether/library/Language/NumPy/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import numpy as np; print('NumPy', np.__version__); import code; code.interact(local={'np': np})" diff --git a/@ether/library/Language/NumPy/run.sh b/@ether/library/Language/NumPy/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/NumPy/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/NumPyro/check.sh b/@ether/library/Language/NumPyro/check.sh new file mode 100755 index 00000000..4eebe563 --- /dev/null +++ b/@ether/library/Language/NumPyro/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import numpyro" >/dev/null 2>&1 diff --git a/@ether/library/Language/NumPyro/install.sh b/@ether/library/Language/NumPyro/install.sh new file mode 100755 index 00000000..40e6f1c8 --- /dev/null +++ b/@ether/library/Language/NumPyro/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing NumPyro from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/pyro-ppl/numpyro" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/pyro-ppl/numpyro.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install . + exit 0 +fi +pip install numpyro diff --git a/@ether/library/Language/NumPyro/repl.sh b/@ether/library/Language/NumPyro/repl.sh new file mode 100755 index 00000000..b6a45fa5 --- /dev/null +++ b/@ether/library/Language/NumPyro/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import numpyro; print('NumPyro', numpyro.__version__); import code; code.interact(local={'numpyro': numpyro})" diff --git a/@ether/library/Language/NumPyro/run.sh b/@ether/library/Language/NumPyro/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/NumPyro/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/Nushell/check.sh b/@ether/library/Language/Nushell/check.sh new file mode 100755 index 00000000..f37bcd40 --- /dev/null +++ b/@ether/library/Language/Nushell/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nu >/dev/null 2>&1 diff --git a/@ether/library/Language/Nushell/install.sh b/@ether/library/Language/Nushell/install.sh new file mode 100755 index 00000000..8ea7a0b8 --- /dev/null +++ b/@ether/library/Language/Nushell/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Nushell from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/nushell/nushell" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/nushell/nushell.git "$REPO_DIR" + fi + cd "$REPO_DIR" + cargo build --release + cp target/release/nu "$HOME/.local/bin/" + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install nushell +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y nushell || { + cargo install nu + } +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y nushell || cargo install nu +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm nushell +else + cargo install nu +fi diff --git a/@ether/library/Language/Nushell/repl.sh b/@ether/library/Language/Nushell/repl.sh new file mode 100755 index 00000000..80f4f018 --- /dev/null +++ b/@ether/library/Language/Nushell/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nu diff --git a/@ether/library/Language/Nushell/run.sh b/@ether/library/Language/Nushell/run.sh new file mode 100755 index 00000000..915ad39d --- /dev/null +++ b/@ether/library/Language/Nushell/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec nu "$@" diff --git a/@ether/library/Language/OCaml/check.sh b/@ether/library/Language/OCaml/check.sh new file mode 100755 index 00000000..3e6d9188 --- /dev/null +++ b/@ether/library/Language/OCaml/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v ocaml >/dev/null 2>&1 diff --git a/@ether/library/Language/OCaml/install.sh b/@ether/library/Language/OCaml/install.sh new file mode 100755 index 00000000..1d1baae3 --- /dev/null +++ b/@ether/library/Language/OCaml/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install opam (OCaml package manager) - https://ocaml.org/install +if [[ "$(uname)" == "Darwin" ]]; then + brew install opam +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y opam +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y opam +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm opam +else + echo "Unsupported package manager." >&2; exit 1 +fi +# Initialize opam (required for a working OCaml environment) +opam init -y --auto-setup --bare +opam switch create default ocaml-base-compiler 2>/dev/null || true +eval "$(opam env)" diff --git a/@ether/library/Language/OCaml/packages.sh b/@ether/library/Language/OCaml/packages.sh new file mode 100755 index 00000000..49039259 --- /dev/null +++ b/@ether/library/Language/OCaml/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="OCaml" +REGISTRIES=( + "opam: https://opam.ocaml.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v opam &>/dev/null; then + opam search "$@" + else + echo "Visit: https://opam.ocaml.org/packages/?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v opam &>/dev/null; then + opam show "$1" + else + echo "Visit: https://opam.ocaml.org/packages/$1/" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + opam install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/OCaml/repl.sh b/@ether/library/Language/OCaml/repl.sh new file mode 100755 index 00000000..97d2b681 --- /dev/null +++ b/@ether/library/Language/OCaml/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec ocaml diff --git a/@ether/library/Language/OCaml/run.sh b/@ether/library/Language/OCaml/run.sh new file mode 100755 index 00000000..84b1fc10 --- /dev/null +++ b/@ether/library/Language/OCaml/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec ocaml "$@" diff --git a/@ether/library/Language/OMDoc/check.sh b/@ether/library/Language/OMDoc/check.sh new file mode 100755 index 00000000..9879df4c --- /dev/null +++ b/@ether/library/Language/OMDoc/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exit 0 diff --git a/@ether/library/Language/OMDoc/install.sh b/@ether/library/Language/OMDoc/install.sh new file mode 100755 index 00000000..8529f542 --- /dev/null +++ b/@ether/library/Language/OMDoc/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "OMDoc is an XML-based markup format for mathematical documents." +echo "No runtime installation required." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/OMDoc/OMDoc" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/OMDoc/OMDoc.git "$REPO_DIR" +fi +echo "OMDoc schema and tools cloned to $REPO_DIR" diff --git a/@ether/library/Language/OMDoc/repl.sh b/@ether/library/Language/OMDoc/repl.sh new file mode 100755 index 00000000..a43e7f71 --- /dev/null +++ b/@ether/library/Language/OMDoc/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "OMDoc is a document format and does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/OMDoc/run.sh b/@ether/library/Language/OMDoc/run.sh new file mode 100755 index 00000000..0755f06a --- /dev/null +++ b/@ether/library/Language/OMDoc/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$@" diff --git a/@ether/library/Language/ONNX/check.sh b/@ether/library/Language/ONNX/check.sh new file mode 100755 index 00000000..65e0bb89 --- /dev/null +++ b/@ether/library/Language/ONNX/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import onnx" >/dev/null 2>&1 diff --git a/@ether/library/Language/ONNX/install.sh b/@ether/library/Language/ONNX/install.sh new file mode 100755 index 00000000..bd07d86b --- /dev/null +++ b/@ether/library/Language/ONNX/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing ONNX from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/onnx/onnx" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/onnx/onnx.git "$REPO_DIR" + fi + cd "$REPO_DIR" + git submodule update --init --recursive + pip install . + exit 0 +fi +pip install onnx diff --git a/@ether/library/Language/ONNX/repl.sh b/@ether/library/Language/ONNX/repl.sh new file mode 100755 index 00000000..76f0423b --- /dev/null +++ b/@ether/library/Language/ONNX/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import onnx; print('ONNX', onnx.__version__); import code; code.interact(local={'onnx': onnx})" diff --git a/@ether/library/Language/ONNX/run.sh b/@ether/library/Language/ONNX/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/ONNX/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/OSH/check.sh b/@ether/library/Language/OSH/check.sh new file mode 100755 index 00000000..7d850ba1 --- /dev/null +++ b/@ether/library/Language/OSH/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v osh >/dev/null 2>&1 diff --git a/@ether/library/Language/OSH/install.sh b/@ether/library/Language/OSH/install.sh new file mode 100755 index 00000000..adc6fa85 --- /dev/null +++ b/@ether/library/Language/OSH/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing OSH (Oils) from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/oils-for-unix/oils" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/oils-for-unix/oils.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./configure + make + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install oils-for-unix +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y oils-for-unix || { + echo "Package not found. Use --from-source." >&2; exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm oils-for-unix +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/OSH/repl.sh b/@ether/library/Language/OSH/repl.sh new file mode 100755 index 00000000..27ed2025 --- /dev/null +++ b/@ether/library/Language/OSH/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec osh diff --git a/@ether/library/Language/OSH/run.sh b/@ether/library/Language/OSH/run.sh new file mode 100755 index 00000000..d28028a6 --- /dev/null +++ b/@ether/library/Language/OSH/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec osh "$@" diff --git a/@ether/library/Language/ObjectiveC/check.sh b/@ether/library/Language/ObjectiveC/check.sh new file mode 100755 index 00000000..cf72d042 --- /dev/null +++ b/@ether/library/Language/ObjectiveC/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v clang >/dev/null 2>&1 || command -v gcc >/dev/null 2>&1 diff --git a/@ether/library/Language/ObjectiveC/install.sh b/@ether/library/Language/ObjectiveC/install.sh new file mode 100755 index 00000000..055b7622 --- /dev/null +++ b/@ether/library/Language/ObjectiveC/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + if ! xcode-select -p >/dev/null 2>&1; then + xcode-select --install + fi + echo "Objective-C is available via Xcode command line tools." +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gobjc gnustep-devel +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gcc-objc gnustep-base-devel +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gcc-objc gnustep-base +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/ObjectiveC/repl.sh b/@ether/library/Language/ObjectiveC/repl.sh new file mode 100755 index 00000000..14bb8a16 --- /dev/null +++ b/@ether/library/Language/ObjectiveC/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Objective-C does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ObjectiveC/run.sh b/@ether/library/Language/ObjectiveC/run.sh new file mode 100755 index 00000000..b66ab10f --- /dev/null +++ b/@ether/library/Language/ObjectiveC/run.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +INPUT="$1"; shift +OUT="$(mktemp)" +if [[ "$(uname)" == "Darwin" ]]; then + clang -framework Foundation -o "$OUT" "$INPUT" "$@" +else + clang $(gnustep-config --objc-flags) $(gnustep-config --objc-libs) -o "$OUT" "$INPUT" "$@" +fi +"$OUT" +rm -f "$OUT" diff --git a/@ether/library/Language/Octave/check.sh b/@ether/library/Language/Octave/check.sh new file mode 100755 index 00000000..2ff63082 --- /dev/null +++ b/@ether/library/Language/Octave/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v octave >/dev/null 2>&1 diff --git a/@ether/library/Language/Octave/install.sh b/@ether/library/Language/Octave/install.sh new file mode 100755 index 00000000..f5764845 --- /dev/null +++ b/@ether/library/Language/Octave/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install octave +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y octave +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y octave +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm octave +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Octave/repl.sh b/@ether/library/Language/Octave/repl.sh new file mode 100755 index 00000000..0cca6e0a --- /dev/null +++ b/@ether/library/Language/Octave/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec octave --no-gui diff --git a/@ether/library/Language/Octave/run.sh b/@ether/library/Language/Octave/run.sh new file mode 100755 index 00000000..a25990ba --- /dev/null +++ b/@ether/library/Language/Octave/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec octave --no-gui "$@" diff --git a/@ether/library/Language/Odin/check.sh b/@ether/library/Language/Odin/check.sh new file mode 100755 index 00000000..604b0219 --- /dev/null +++ b/@ether/library/Language/Odin/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v odin >/dev/null 2>&1 diff --git a/@ether/library/Language/Odin/install.sh b/@ether/library/Language/Odin/install.sh new file mode 100755 index 00000000..ad5e2edd --- /dev/null +++ b/@ether/library/Language/Odin/install.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Odin from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/odin-lang/Odin" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/odin-lang/Odin.git "$REPO_DIR" + fi + cd "$REPO_DIR" + make + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install odin +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm odin +else + echo "No official package available. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Odin/repl.sh b/@ether/library/Language/Odin/repl.sh new file mode 100755 index 00000000..d8fad871 --- /dev/null +++ b/@ether/library/Language/Odin/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Odin does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Odin/run.sh b/@ether/library/Language/Odin/run.sh new file mode 100755 index 00000000..dfe4ed24 --- /dev/null +++ b/@ether/library/Language/Odin/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec odin run "$@" diff --git a/@ether/library/Language/OpenQASM/check.sh b/@ether/library/Language/OpenQASM/check.sh new file mode 100755 index 00000000..4f4b66d1 --- /dev/null +++ b/@ether/library/Language/OpenQASM/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import openqasm3" >/dev/null 2>&1 diff --git a/@ether/library/Language/OpenQASM/install.sh b/@ether/library/Language/OpenQASM/install.sh new file mode 100755 index 00000000..4741825b --- /dev/null +++ b/@ether/library/Language/OpenQASM/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing OpenQASM from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/openqasm/openqasm" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/openqasm/openqasm.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install . + exit 0 +fi +pip install openqasm3 diff --git a/@ether/library/Language/OpenQASM/repl.sh b/@ether/library/Language/OpenQASM/repl.sh new file mode 100755 index 00000000..c34ee75c --- /dev/null +++ b/@ether/library/Language/OpenQASM/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import openqasm3; import code; code.interact(local={'openqasm3': openqasm3})" diff --git a/@ether/library/Language/OpenQASM/run.sh b/@ether/library/Language/OpenQASM/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/OpenQASM/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/OpenQL/check.sh b/@ether/library/Language/OpenQL/check.sh new file mode 100755 index 00000000..821a790d --- /dev/null +++ b/@ether/library/Language/OpenQL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import openql" >/dev/null 2>&1 diff --git a/@ether/library/Language/OpenQL/install.sh b/@ether/library/Language/OpenQL/install.sh new file mode 100755 index 00000000..331860d4 --- /dev/null +++ b/@ether/library/Language/OpenQL/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing OpenQL from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/QuTech-Delft/OpenQL" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/QuTech-Delft/OpenQL.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install . + exit 0 +fi +pip install qutechopenql diff --git a/@ether/library/Language/OpenQL/repl.sh b/@ether/library/Language/OpenQL/repl.sh new file mode 100755 index 00000000..b3e12bb2 --- /dev/null +++ b/@ether/library/Language/OpenQL/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import openql; import code; code.interact(local={'openql': openql})" diff --git a/@ether/library/Language/OpenQL/run.sh b/@ether/library/Language/OpenQL/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/OpenQL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/OpenSCAD/check.sh b/@ether/library/Language/OpenSCAD/check.sh new file mode 100755 index 00000000..726ce3b5 --- /dev/null +++ b/@ether/library/Language/OpenSCAD/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v openscad >/dev/null 2>&1 diff --git a/@ether/library/Language/OpenSCAD/install.sh b/@ether/library/Language/OpenSCAD/install.sh new file mode 100755 index 00000000..e7d643d5 --- /dev/null +++ b/@ether/library/Language/OpenSCAD/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# OpenSCAD - programmable CAD modeller +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask openscad +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y openscad +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y openscad +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm openscad +else + echo "Unsupported package manager. Download from https://openscad.org/downloads.html" >&2; exit 1 +fi diff --git a/@ether/library/Language/OpenSCAD/packages.sh b/@ether/library/Language/OpenSCAD/packages.sh new file mode 100755 index 00000000..9886637c --- /dev/null +++ b/@ether/library/Language/OpenSCAD/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "OpenSCAD does not have a standard package manager." +echo "MCAD Library: https://github.com/openscad/MCAD" diff --git a/@ether/library/Language/OpenSCAD/repl.sh b/@ether/library/Language/OpenSCAD/repl.sh new file mode 100755 index 00000000..ef9174a6 --- /dev/null +++ b/@ether/library/Language/OpenSCAD/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "OpenSCAD does not have a text REPL. Use the GUI: openscad" diff --git a/@ether/library/Language/OpenSCAD/run.sh b/@ether/library/Language/OpenSCAD/run.sh new file mode 100755 index 00000000..0b99e4a9 --- /dev/null +++ b/@ether/library/Language/OpenSCAD/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec openscad "$@" diff --git a/@ether/library/Language/OpenTheory/check.sh b/@ether/library/Language/OpenTheory/check.sh new file mode 100755 index 00000000..6b452770 --- /dev/null +++ b/@ether/library/Language/OpenTheory/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v opentheory >/dev/null 2>&1 diff --git a/@ether/library/Language/OpenTheory/install.sh b/@ether/library/Language/OpenTheory/install.sh new file mode 100755 index 00000000..73c3585b --- /dev/null +++ b/@ether/library/Language/OpenTheory/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "OpenTheory is a standard for sharing HOL theorem prover theories." +echo "The opentheory tool can be installed via the OpenTheory project." +echo "See http://www.gilith.com/opentheory/ for installation instructions." +if command -v cabal >/dev/null 2>&1; then + cabal update && cabal install opentheory +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y opentheory || { + echo "Package not found. Install via cabal or from source." >&2; exit 1 + } +else + echo "Install Haskell/cabal first, then: cabal install opentheory" >&2; exit 1 +fi diff --git a/@ether/library/Language/OpenTheory/repl.sh b/@ether/library/Language/OpenTheory/repl.sh new file mode 100755 index 00000000..2e1500f2 --- /dev/null +++ b/@ether/library/Language/OpenTheory/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "OpenTheory does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/OpenTheory/run.sh b/@ether/library/Language/OpenTheory/run.sh new file mode 100755 index 00000000..b5986ad9 --- /dev/null +++ b/@ether/library/Language/OpenTheory/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec opentheory "$@" diff --git a/@ether/library/Language/OpetopeTypeTheory/check.sh b/@ether/library/Language/OpetopeTypeTheory/check.sh new file mode 100755 index 00000000..307b2c69 --- /dev/null +++ b/@ether/library/Language/OpetopeTypeTheory/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ericfinster/opetopic-types" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/OpetopeTypeTheory/install.sh b/@ether/library/Language/OpetopeTypeTheory/install.sh new file mode 100755 index 00000000..0dc23232 --- /dev/null +++ b/@ether/library/Language/OpetopeTypeTheory/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Opetopic Type Theory from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ericfinster/opetopic-types" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ericfinster/opetopic-types.git "$REPO_DIR" +fi +cd "$REPO_DIR" +echo "Source cloned to $REPO_DIR. See README for build instructions." diff --git a/@ether/library/Language/OpetopeTypeTheory/repl.sh b/@ether/library/Language/OpetopeTypeTheory/repl.sh new file mode 100755 index 00000000..20d3b4ec --- /dev/null +++ b/@ether/library/Language/OpetopeTypeTheory/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Opetopic Type Theory does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/OpetopeTypeTheory/run.sh b/@ether/library/Language/OpetopeTypeTheory/run.sh new file mode 100755 index 00000000..dcb3af0d --- /dev/null +++ b/@ether/library/Language/OpetopeTypeTheory/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Opetopic Type Theory does not have a standalone runner." >&2 +exit 1 diff --git a/@ether/library/Language/Orca/check.sh b/@ether/library/Language/Orca/check.sh new file mode 100755 index 00000000..1a0b3abe --- /dev/null +++ b/@ether/library/Language/Orca/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v orca >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hundredrabbits/Orca" + [[ -d "$REPO_DIR" ]] +} diff --git a/@ether/library/Language/Orca/install.sh b/@ether/library/Language/Orca/install.sh new file mode 100755 index 00000000..ef52c719 --- /dev/null +++ b/@ether/library/Language/Orca/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Orca from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hundredrabbits/Orca" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/hundredrabbits/Orca.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if [[ -f "package.json" ]]; then + npm install +fi +echo "Orca cloned to $REPO_DIR." diff --git a/@ether/library/Language/Orca/repl.sh b/@ether/library/Language/Orca/repl.sh new file mode 100755 index 00000000..225cdd0d --- /dev/null +++ b/@ether/library/Language/Orca/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v orca >/dev/null 2>&1; then + exec orca +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hundredrabbits/Orca" +cd "$REPO_DIR" +exec npm start diff --git a/@ether/library/Language/Orca/run.sh b/@ether/library/Language/Orca/run.sh new file mode 100755 index 00000000..3de33d42 --- /dev/null +++ b/@ether/library/Language/Orca/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v orca >/dev/null 2>&1; then + exec orca "$@" +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hundredrabbits/Orca" +cd "$REPO_DIR" +exec npm start -- "$@" diff --git a/@ether/library/Language/Ott/check.sh b/@ether/library/Language/Ott/check.sh new file mode 100755 index 00000000..a92914dc --- /dev/null +++ b/@ether/library/Language/Ott/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v ott >/dev/null 2>&1 diff --git a/@ether/library/Language/Ott/install.sh b/@ether/library/Language/Ott/install.sh new file mode 100755 index 00000000..51429a48 --- /dev/null +++ b/@ether/library/Language/Ott/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Ott from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ott-lang/ott" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ott-lang/ott.git "$REPO_DIR" + fi + cd "$REPO_DIR" + make + sudo make install + exit 0 +fi +if command -v opam >/dev/null 2>&1; then + opam install ott -y +elif [[ "$(uname)" == "Darwin" ]]; then + brew install ott +else + echo "Install via opam: opam install ott" >&2; exit 1 +fi diff --git a/@ether/library/Language/Ott/repl.sh b/@ether/library/Language/Ott/repl.sh new file mode 100755 index 00000000..bc655501 --- /dev/null +++ b/@ether/library/Language/Ott/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Ott does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Ott/run.sh b/@ether/library/Language/Ott/run.sh new file mode 100755 index 00000000..fdf35738 --- /dev/null +++ b/@ether/library/Language/Ott/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ott "$@" diff --git a/@ether/library/Language/Otter/check.sh b/@ether/library/Language/Otter/check.sh new file mode 100755 index 00000000..4848e2a8 --- /dev/null +++ b/@ether/library/Language/Otter/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v otter >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/theoremprover-museum/otter" + [[ -d "$REPO_DIR" ]] +} diff --git a/@ether/library/Language/Otter/install.sh b/@ether/library/Language/Otter/install.sh new file mode 100755 index 00000000..c0bbf8a3 --- /dev/null +++ b/@ether/library/Language/Otter/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Otter from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/theoremprover-museum/otter" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/theoremprover-museum/otter.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if [[ -f Makefile ]]; then + make -j"$(nproc)" +fi +echo "Otter source cloned to $REPO_DIR. See README for build instructions." diff --git a/@ether/library/Language/Otter/repl.sh b/@ether/library/Language/Otter/repl.sh new file mode 100755 index 00000000..3ed2bac2 --- /dev/null +++ b/@ether/library/Language/Otter/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec otter diff --git a/@ether/library/Language/Otter/run.sh b/@ether/library/Language/Otter/run.sh new file mode 100755 index 00000000..b99bbf5d --- /dev/null +++ b/@ether/library/Language/Otter/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec otter "$@" diff --git a/@ether/library/Language/PHP/check.sh b/@ether/library/Language/PHP/check.sh new file mode 100755 index 00000000..1a4e373d --- /dev/null +++ b/@ether/library/Language/PHP/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v php >/dev/null 2>&1 diff --git a/@ether/library/Language/PHP/install.sh b/@ether/library/Language/PHP/install.sh new file mode 100755 index 00000000..2150fd43 --- /dev/null +++ b/@ether/library/Language/PHP/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing PHP from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/php/php-src" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/php/php-src.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./buildconf + ./configure --prefix="$HOME/.local" + make -j"$(nproc)" + make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install php +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y php-cli +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y php-cli +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm php +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/PHP/packages.sh b/@ether/library/Language/PHP/packages.sh new file mode 100755 index 00000000..308a58fb --- /dev/null +++ b/@ether/library/Language/PHP/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="PHP" +REGISTRIES=( + "Packagist: https://packagist.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v composer &>/dev/null; then + composer search "$@" + else + echo "Visit: https://packagist.org/?query=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v composer &>/dev/null; then + composer show "$1" 2>/dev/null || echo "Visit: https://packagist.org/packages/$1" + else + echo "Visit: https://packagist.org/packages/$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + composer require "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/PHP/repl.sh b/@ether/library/Language/PHP/repl.sh new file mode 100755 index 00000000..8c4dc3cc --- /dev/null +++ b/@ether/library/Language/PHP/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec php -a diff --git a/@ether/library/Language/PHP/run.sh b/@ether/library/Language/PHP/run.sh new file mode 100755 index 00000000..e4f41803 --- /dev/null +++ b/@ether/library/Language/PHP/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec php "$@" diff --git a/@ether/library/Language/PMTK/check.sh b/@ether/library/Language/PMTK/check.sh new file mode 100755 index 00000000..fa6b3363 --- /dev/null +++ b/@ether/library/Language/PMTK/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v octave >/dev/null 2>&1 || command -v matlab >/dev/null 2>&1 diff --git a/@ether/library/Language/PMTK/install.sh b/@ether/library/Language/PMTK/install.sh new file mode 100755 index 00000000..21bc4071 --- /dev/null +++ b/@ether/library/Language/PMTK/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing PMTK3 from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/probml/pmtk3" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/probml/pmtk3.git "$REPO_DIR" +fi +echo "PMTK3 cloned to $REPO_DIR. Requires MATLAB or GNU Octave." diff --git a/@ether/library/Language/PMTK/repl.sh b/@ether/library/Language/PMTK/repl.sh new file mode 100755 index 00000000..0cca6e0a --- /dev/null +++ b/@ether/library/Language/PMTK/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec octave --no-gui diff --git a/@ether/library/Language/PMTK/run.sh b/@ether/library/Language/PMTK/run.sh new file mode 100755 index 00000000..a25990ba --- /dev/null +++ b/@ether/library/Language/PMTK/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec octave --no-gui "$@" diff --git a/@ether/library/Language/PProgrammingLanguageforAsync/check.sh b/@ether/library/Language/PProgrammingLanguageforAsync/check.sh new file mode 100755 index 00000000..39ec3ceb --- /dev/null +++ b/@ether/library/Language/PProgrammingLanguageforAsync/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v p >/dev/null 2>&1 || dotnet tool list -g 2>/dev/null | grep -qi "^p " diff --git a/@ether/library/Language/PProgrammingLanguageforAsync/install.sh b/@ether/library/Language/PProgrammingLanguageforAsync/install.sh new file mode 100755 index 00000000..b9ad01a2 --- /dev/null +++ b/@ether/library/Language/PProgrammingLanguageforAsync/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing P from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/p-org/P" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/p-org/P.git "$REPO_DIR" + fi + cd "$REPO_DIR" + dotnet build + exit 0 +fi +dotnet tool install --global P diff --git a/@ether/library/Language/PProgrammingLanguageforAsync/repl.sh b/@ether/library/Language/PProgrammingLanguageforAsync/repl.sh new file mode 100755 index 00000000..5548505a --- /dev/null +++ b/@ether/library/Language/PProgrammingLanguageforAsync/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "P does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/PProgrammingLanguageforAsync/run.sh b/@ether/library/Language/PProgrammingLanguageforAsync/run.sh new file mode 100755 index 00000000..1812db9e --- /dev/null +++ b/@ether/library/Language/PProgrammingLanguageforAsync/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec p compile "$@" diff --git a/@ether/library/Language/PRISM/check.sh b/@ether/library/Language/PRISM/check.sh new file mode 100755 index 00000000..97d78117 --- /dev/null +++ b/@ether/library/Language/PRISM/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v prism >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/prismplp/prism" + [[ -d "$REPO_DIR" ]] +} diff --git a/@ether/library/Language/PRISM/install.sh b/@ether/library/Language/PRISM/install.sh new file mode 100755 index 00000000..71f0b901 --- /dev/null +++ b/@ether/library/Language/PRISM/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing PRISM from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/prismplp/prism" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/prismplp/prism.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if [[ -f Makefile ]]; then + make +fi +echo "PRISM cloned to $REPO_DIR. See README for build instructions." diff --git a/@ether/library/Language/PRISM/repl.sh b/@ether/library/Language/PRISM/repl.sh new file mode 100755 index 00000000..31e5b850 --- /dev/null +++ b/@ether/library/Language/PRISM/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec prism diff --git a/@ether/library/Language/PRISM/run.sh b/@ether/library/Language/PRISM/run.sh new file mode 100755 index 00000000..31a12277 --- /dev/null +++ b/@ether/library/Language/PRISM/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec prism "$@" diff --git a/@ether/library/Language/PSI/check.sh b/@ether/library/Language/PSI/check.sh new file mode 100755 index 00000000..b7525362 --- /dev/null +++ b/@ether/library/Language/PSI/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/eth-sri/psi" +[[ -x "$REPO_DIR/psi" ]] diff --git a/@ether/library/Language/PSI/install.sh b/@ether/library/Language/PSI/install.sh new file mode 100755 index 00000000..f4f3b979 --- /dev/null +++ b/@ether/library/Language/PSI/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/eth-sri/psi" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/eth-sri/psi.git "$REPO_DIR" +fi +cd "$REPO_DIR" +./build.sh diff --git a/@ether/library/Language/PSI/repl.sh b/@ether/library/Language/PSI/repl.sh new file mode 100755 index 00000000..6e0091bd --- /dev/null +++ b/@ether/library/Language/PSI/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "PSI does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/PSI/run.sh b/@ether/library/Language/PSI/run.sh new file mode 100755 index 00000000..182abfdc --- /dev/null +++ b/@ether/library/Language/PSI/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/eth-sri/psi" +exec "$REPO_DIR/psi" "$1" diff --git a/@ether/library/Language/PSQL/check.sh b/@ether/library/Language/PSQL/check.sh new file mode 100755 index 00000000..2f907698 --- /dev/null +++ b/@ether/library/Language/PSQL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v psql >/dev/null 2>&1 diff --git a/@ether/library/Language/PSQL/install.sh b/@ether/library/Language/PSQL/install.sh new file mode 100755 index 00000000..d8c1d698 --- /dev/null +++ b/@ether/library/Language/PSQL/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install postgresql +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y postgresql-client +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y postgresql +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm postgresql +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/PSQL/repl.sh b/@ether/library/Language/PSQL/repl.sh new file mode 100755 index 00000000..8ea6b1f7 --- /dev/null +++ b/@ether/library/Language/PSQL/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec psql diff --git a/@ether/library/Language/PSQL/run.sh b/@ether/library/Language/PSQL/run.sh new file mode 100755 index 00000000..23d93291 --- /dev/null +++ b/@ether/library/Language/PSQL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec psql -f "$1" diff --git a/@ether/library/Language/PVS/check.sh b/@ether/library/Language/PVS/check.sh new file mode 100755 index 00000000..c2354204 --- /dev/null +++ b/@ether/library/Language/PVS/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v pvs >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/SRI-CSL/PVS" + [[ -x "$REPO_DIR/pvs" ]] +} diff --git a/@ether/library/Language/PVS/install.sh b/@ether/library/Language/PVS/install.sh new file mode 100755 index 00000000..80d0649e --- /dev/null +++ b/@ether/library/Language/PVS/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/SRI-CSL/PVS" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/SRI-CSL/PVS.git "$REPO_DIR" +fi +cd "$REPO_DIR" +./configure && make diff --git a/@ether/library/Language/PVS/repl.sh b/@ether/library/Language/PVS/repl.sh new file mode 100755 index 00000000..b8f8b850 --- /dev/null +++ b/@ether/library/Language/PVS/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v pvs >/dev/null 2>&1; then + exec pvs +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/SRI-CSL/PVS" + exec "$REPO_DIR/pvs" +fi diff --git a/@ether/library/Language/PVS/run.sh b/@ether/library/Language/PVS/run.sh new file mode 100755 index 00000000..9c216128 --- /dev/null +++ b/@ether/library/Language/PVS/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v pvs >/dev/null 2>&1; then + exec pvs "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/SRI-CSL/PVS" + exec "$REPO_DIR/pvs" "$1" +fi diff --git a/@ether/library/Language/PWhile/check.sh b/@ether/library/Language/PWhile/check.sh new file mode 100755 index 00000000..053df151 --- /dev/null +++ b/@ether/library/Language/PWhile/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zz5013/pwCompiler" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/PWhile/install.sh b/@ether/library/Language/PWhile/install.sh new file mode 100755 index 00000000..a8312d9b --- /dev/null +++ b/@ether/library/Language/PWhile/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zz5013/pwCompiler" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/zz5013/pwCompiler.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make diff --git a/@ether/library/Language/PWhile/repl.sh b/@ether/library/Language/PWhile/repl.sh new file mode 100755 index 00000000..399ccba4 --- /dev/null +++ b/@ether/library/Language/PWhile/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "PWhile does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/PWhile/run.sh b/@ether/library/Language/PWhile/run.sh new file mode 100755 index 00000000..7d86d663 --- /dev/null +++ b/@ether/library/Language/PWhile/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zz5013/pwCompiler" +exec "$REPO_DIR/pwc" "$1" diff --git a/@ether/library/Language/Pact/check.sh b/@ether/library/Language/Pact/check.sh new file mode 100755 index 00000000..867ed119 --- /dev/null +++ b/@ether/library/Language/Pact/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v pact >/dev/null 2>&1 diff --git a/@ether/library/Language/Pact/install.sh b/@ether/library/Language/Pact/install.sh new file mode 100755 index 00000000..ceb1fe75 --- /dev/null +++ b/@ether/library/Language/Pact/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Pact from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/kadena-io/pact" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/kadena-io/pact.git "$REPO_DIR" + fi + cd "$REPO_DIR" + cabal build + cabal install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install kadena-io/pact/pact +elif command -v nix >/dev/null 2>&1; then + nix profile install github:kadena-io/pact +else + echo "Install via brew (macOS), nix, or from source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Pact/repl.sh b/@ether/library/Language/Pact/repl.sh new file mode 100755 index 00000000..2bb86108 --- /dev/null +++ b/@ether/library/Language/Pact/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec pact diff --git a/@ether/library/Language/Pact/run.sh b/@ether/library/Language/Pact/run.sh new file mode 100755 index 00000000..89d27008 --- /dev/null +++ b/@ether/library/Language/Pact/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec pact "$@" diff --git a/@ether/library/Language/Pandoc/check.sh b/@ether/library/Language/Pandoc/check.sh new file mode 100755 index 00000000..8c2c6495 --- /dev/null +++ b/@ether/library/Language/Pandoc/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v pandoc >/dev/null 2>&1 diff --git a/@ether/library/Language/Pandoc/install.sh b/@ether/library/Language/Pandoc/install.sh new file mode 100755 index 00000000..dd516aec --- /dev/null +++ b/@ether/library/Language/Pandoc/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Pandoc from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/jgm/pandoc" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/jgm/pandoc.git "$REPO_DIR" + fi + cd "$REPO_DIR" + cabal build + cabal install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install pandoc +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y pandoc +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y pandoc +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm pandoc +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Pandoc/repl.sh b/@ether/library/Language/Pandoc/repl.sh new file mode 100755 index 00000000..4a79692b --- /dev/null +++ b/@ether/library/Language/Pandoc/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Pandoc does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Pandoc/run.sh b/@ether/library/Language/Pandoc/run.sh new file mode 100755 index 00000000..1398f3fb --- /dev/null +++ b/@ether/library/Language/Pandoc/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec pandoc "$@" diff --git a/@ether/library/Language/PaperProof/check.sh b/@ether/library/Language/PaperProof/check.sh new file mode 100755 index 00000000..d3848b62 --- /dev/null +++ b/@ether/library/Language/PaperProof/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Paper-Proof/paperproof" +[[ -d "$REPO_DIR/node_modules" ]] diff --git a/@ether/library/Language/PaperProof/install.sh b/@ether/library/Language/PaperProof/install.sh new file mode 100755 index 00000000..ce55532e --- /dev/null +++ b/@ether/library/Language/PaperProof/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing PaperProof from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Paper-Proof/paperproof" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Paper-Proof/paperproof.git "$REPO_DIR" +fi +cd "$REPO_DIR" +npm install +echo "PaperProof installed at $REPO_DIR." diff --git a/@ether/library/Language/PaperProof/repl.sh b/@ether/library/Language/PaperProof/repl.sh new file mode 100755 index 00000000..20f96e0b --- /dev/null +++ b/@ether/library/Language/PaperProof/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "PaperProof does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/PaperProof/run.sh b/@ether/library/Language/PaperProof/run.sh new file mode 100755 index 00000000..73a54e69 --- /dev/null +++ b/@ether/library/Language/PaperProof/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Paper-Proof/paperproof" +cd "$REPO_DIR" +exec npm start -- "$@" diff --git a/@ether/library/Language/Par/check.sh b/@ether/library/Language/Par/check.sh new file mode 100755 index 00000000..6feb7b43 --- /dev/null +++ b/@ether/library/Language/Par/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v par >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/faiface/par-lang" + [[ -x "$REPO_DIR/target/release/par" ]] +} diff --git a/@ether/library/Language/Par/install.sh b/@ether/library/Language/Par/install.sh new file mode 100755 index 00000000..29504f57 --- /dev/null +++ b/@ether/library/Language/Par/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing Par from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/faiface/par-lang" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/faiface/par-lang.git "$REPO_DIR" +fi +cd "$REPO_DIR" +cargo build --release +cp target/release/par "$HOME/.local/bin/" 2>/dev/null || true diff --git a/@ether/library/Language/Par/repl.sh b/@ether/library/Language/Par/repl.sh new file mode 100755 index 00000000..522b1149 --- /dev/null +++ b/@ether/library/Language/Par/repl.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v par >/dev/null 2>&1; then + exec par +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/faiface/par-lang" +exec "$REPO_DIR/target/release/par" diff --git a/@ether/library/Language/Par/run.sh b/@ether/library/Language/Par/run.sh new file mode 100755 index 00000000..98bc37a8 --- /dev/null +++ b/@ether/library/Language/Par/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v par >/dev/null 2>&1; then + exec par "$@" +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/faiface/par-lang" +exec "$REPO_DIR/target/release/par" "$@" diff --git a/@ether/library/Language/Parquet/check.sh b/@ether/library/Language/Parquet/check.sh new file mode 100755 index 00000000..9879df4c --- /dev/null +++ b/@ether/library/Language/Parquet/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exit 0 diff --git a/@ether/library/Language/Parquet/install.sh b/@ether/library/Language/Parquet/install.sh new file mode 100755 index 00000000..4bbf3086 --- /dev/null +++ b/@ether/library/Language/Parquet/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Parquet is a columnar data storage format. No runtime installation required." +echo "Installing parquet-tools for viewing files..." +pip install parquet-tools 2>/dev/null || pip install pyarrow 2>/dev/null || true diff --git a/@ether/library/Language/Parquet/repl.sh b/@ether/library/Language/Parquet/repl.sh new file mode 100755 index 00000000..fe2e2552 --- /dev/null +++ b/@ether/library/Language/Parquet/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Parquet is a data format and does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Parquet/run.sh b/@ether/library/Language/Parquet/run.sh new file mode 100755 index 00000000..c4f4dc5b --- /dev/null +++ b/@ether/library/Language/Parquet/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v parquet-tools >/dev/null 2>&1; then + exec parquet-tools show "$@" +fi +exec python3 -c "import pyarrow.parquet as pq; import sys; print(pq.read_table(sys.argv[1]).to_pandas())" "$@" diff --git a/@ether/library/Language/Pascal/check.sh b/@ether/library/Language/Pascal/check.sh new file mode 100755 index 00000000..d53ae64d --- /dev/null +++ b/@ether/library/Language/Pascal/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v fpc >/dev/null 2>&1 diff --git a/@ether/library/Language/Pascal/install.sh b/@ether/library/Language/Pascal/install.sh new file mode 100755 index 00000000..352081ab --- /dev/null +++ b/@ether/library/Language/Pascal/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install fpc +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y fpc +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y fpc +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm fpc +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Pascal/repl.sh b/@ether/library/Language/Pascal/repl.sh new file mode 100755 index 00000000..e2f19cf5 --- /dev/null +++ b/@ether/library/Language/Pascal/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Pascal (Free Pascal) does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Pascal/run.sh b/@ether/library/Language/Pascal/run.sh new file mode 100755 index 00000000..4efba381 --- /dev/null +++ b/@ether/library/Language/Pascal/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +INPUT="$1"; shift +OUT="$(mktemp)" +fpc -o"$OUT" "$INPUT" +"$OUT" "$@" +rm -f "$OUT" diff --git a/@ether/library/Language/PennyLane/check.sh b/@ether/library/Language/PennyLane/check.sh new file mode 100755 index 00000000..e838fbae --- /dev/null +++ b/@ether/library/Language/PennyLane/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import pennylane" >/dev/null 2>&1 diff --git a/@ether/library/Language/PennyLane/install.sh b/@ether/library/Language/PennyLane/install.sh new file mode 100755 index 00000000..b2b6fb10 --- /dev/null +++ b/@ether/library/Language/PennyLane/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing PennyLane from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/PennyLaneAI/pennylane" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/PennyLaneAI/pennylane.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install -e . + exit 0 +fi +pip install pennylane diff --git a/@ether/library/Language/PennyLane/repl.sh b/@ether/library/Language/PennyLane/repl.sh new file mode 100755 index 00000000..74dd9f48 --- /dev/null +++ b/@ether/library/Language/PennyLane/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import pennylane as qml; print('PennyLane', qml.__version__); import code; code.interact(local={'qml': qml})" diff --git a/@ether/library/Language/PennyLane/run.sh b/@ether/library/Language/PennyLane/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/PennyLane/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/Perl/check.sh b/@ether/library/Language/Perl/check.sh new file mode 100755 index 00000000..9ec84b67 --- /dev/null +++ b/@ether/library/Language/Perl/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v perl >/dev/null 2>&1 diff --git a/@ether/library/Language/Perl/install.sh b/@ether/library/Language/Perl/install.sh new file mode 100755 index 00000000..062fcf56 --- /dev/null +++ b/@ether/library/Language/Perl/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install perl +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y perl +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y perl +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm perl +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Perl/packages.sh b/@ether/library/Language/Perl/packages.sh new file mode 100755 index 00000000..34aeb5a5 --- /dev/null +++ b/@ether/library/Language/Perl/packages.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Perl" +REGISTRIES=( + "MetaCPAN: https://metacpan.org" + "CPAN: https://www.cpan.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v cpan &>/dev/null; then + cpan -D "$1" 2>/dev/null || echo "Visit: https://metacpan.org/search?q=$1" + else + echo "Visit: https://metacpan.org/search?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v perldoc &>/dev/null; then + perldoc "$1" 2>/dev/null || echo "Visit: https://metacpan.org/pod/$1" + else + echo "Visit: https://metacpan.org/pod/$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + if command -v cpanm &>/dev/null; then + cpanm "$1" + elif command -v cpan &>/dev/null; then + cpan "$1" + else + echo "Install cpanminus first: curl -L https://cpanmin.us | perl - --sudo App::cpanminus" + fi + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Perl/repl.sh b/@ether/library/Language/Perl/repl.sh new file mode 100755 index 00000000..f09fbf8d --- /dev/null +++ b/@ether/library/Language/Perl/repl.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v reply >/dev/null 2>&1; then + exec reply +fi +exec perl -de0 diff --git a/@ether/library/Language/Perl/run.sh b/@ether/library/Language/Perl/run.sh new file mode 100755 index 00000000..de739eaa --- /dev/null +++ b/@ether/library/Language/Perl/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec perl "$@" diff --git a/@ether/library/Language/PhoX/check.sh b/@ether/library/Language/PhoX/check.sh new file mode 100755 index 00000000..d31750b5 --- /dev/null +++ b/@ether/library/Language/PhoX/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v phox >/dev/null 2>&1 diff --git a/@ether/library/Language/PhoX/install.sh b/@ether/library/Language/PhoX/install.sh new file mode 100755 index 00000000..c4a48fbe --- /dev/null +++ b/@ether/library/Language/PhoX/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "PhoX is a proof assistant." +echo "See https://raffalli.eu/phox/index.html for download and installation instructions." +if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y phox || { + echo "PhoX not found in repositories. Install from source at https://raffalli.eu/phox/" >&2; exit 1 + } +else + echo "Install PhoX from https://raffalli.eu/phox/" >&2; exit 1 +fi diff --git a/@ether/library/Language/PhoX/repl.sh b/@ether/library/Language/PhoX/repl.sh new file mode 100755 index 00000000..2f4fdb5d --- /dev/null +++ b/@ether/library/Language/PhoX/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec phox diff --git a/@ether/library/Language/PhoX/run.sh b/@ether/library/Language/PhoX/run.sh new file mode 100755 index 00000000..a58ef74c --- /dev/null +++ b/@ether/library/Language/PhoX/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec phox "$@" diff --git a/@ether/library/Language/Picat/check.sh b/@ether/library/Language/Picat/check.sh new file mode 100755 index 00000000..edd84fc8 --- /dev/null +++ b/@ether/library/Language/Picat/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v picat >/dev/null 2>&1 diff --git a/@ether/library/Language/Picat/install.sh b/@ether/library/Language/Picat/install.sh new file mode 100755 index 00000000..52a0d38f --- /dev/null +++ b/@ether/library/Language/Picat/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Picat from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mingodad/picat" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/mingodad/picat.git "$REPO_DIR" + fi + cd "$REPO_DIR" + if [[ -d emu ]]; then + cd emu + make -f Makefile.linux + fi + exit 0 +fi +echo "Download Picat from https://picat-lang.org/download.html" +echo "Extract and add to PATH." +exit 1 diff --git a/@ether/library/Language/Picat/repl.sh b/@ether/library/Language/Picat/repl.sh new file mode 100755 index 00000000..50021c4a --- /dev/null +++ b/@ether/library/Language/Picat/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec picat diff --git a/@ether/library/Language/Picat/run.sh b/@ether/library/Language/Picat/run.sh new file mode 100755 index 00000000..4b605436 --- /dev/null +++ b/@ether/library/Language/Picat/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec picat "$@" diff --git a/@ether/library/Language/PicoSAT/check.sh b/@ether/library/Language/PicoSAT/check.sh new file mode 100755 index 00000000..f75c0e86 --- /dev/null +++ b/@ether/library/Language/PicoSAT/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v picosat >/dev/null 2>&1 diff --git a/@ether/library/Language/PicoSAT/install.sh b/@ether/library/Language/PicoSAT/install.sh new file mode 100755 index 00000000..d6634630 --- /dev/null +++ b/@ether/library/Language/PicoSAT/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install picosat +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y picosat +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y picosat +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm picosat +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/PicoSAT/repl.sh b/@ether/library/Language/PicoSAT/repl.sh new file mode 100755 index 00000000..7c1d8d99 --- /dev/null +++ b/@ether/library/Language/PicoSAT/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "PicoSAT does not have an interactive REPL. Provide a .cnf file." >&2 +exit 1 diff --git a/@ether/library/Language/PicoSAT/run.sh b/@ether/library/Language/PicoSAT/run.sh new file mode 100755 index 00000000..a59f8d6c --- /dev/null +++ b/@ether/library/Language/PicoSAT/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec picosat "$@" diff --git a/@ether/library/Language/Picture/check.sh b/@ether/library/Language/Picture/check.sh new file mode 100755 index 00000000..559e8cc8 --- /dev/null +++ b/@ether/library/Language/Picture/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mrkulk/MIT-Picture" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/Picture/install.sh b/@ether/library/Language/Picture/install.sh new file mode 100755 index 00000000..84b83a27 --- /dev/null +++ b/@ether/library/Language/Picture/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing MIT-Picture from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mrkulk/MIT-Picture" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/mrkulk/MIT-Picture.git "$REPO_DIR" +fi +echo "MIT-Picture source cloned to $REPO_DIR." +echo "Requires Julia. See README for setup instructions." diff --git a/@ether/library/Language/Picture/repl.sh b/@ether/library/Language/Picture/repl.sh new file mode 100755 index 00000000..401e14c2 --- /dev/null +++ b/@ether/library/Language/Picture/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec julia diff --git a/@ether/library/Language/Picture/run.sh b/@ether/library/Language/Picture/run.sh new file mode 100755 index 00000000..6afc8fc0 --- /dev/null +++ b/@ether/library/Language/Picture/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec julia "$@" diff --git a/@ether/library/Language/Piet/check.sh b/@ether/library/Language/Piet/check.sh new file mode 100755 index 00000000..229abab9 --- /dev/null +++ b/@ether/library/Language/Piet/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v npiet >/dev/null 2>&1 diff --git a/@ether/library/Language/Piet/install.sh b/@ether/library/Language/Piet/install.sh new file mode 100755 index 00000000..88c57f06 --- /dev/null +++ b/@ether/library/Language/Piet/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing npiet (Piet interpreter)..." +if [[ "$(uname)" == "Darwin" ]]; then + brew install npiet +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y npiet || { + echo "npiet not in repositories. Download from https://www.bertnase.de/npiet/" >&2; exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm npiet || { + echo "npiet not in repositories. Download from https://www.bertnase.de/npiet/" >&2; exit 1 + } +else + echo "Download npiet from https://www.bertnase.de/npiet/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Piet/repl.sh b/@ether/library/Language/Piet/repl.sh new file mode 100755 index 00000000..e660bf2f --- /dev/null +++ b/@ether/library/Language/Piet/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Piet does not have an interactive REPL. Provide an image file." >&2 +exit 1 diff --git a/@ether/library/Language/Piet/run.sh b/@ether/library/Language/Piet/run.sh new file mode 100755 index 00000000..3d66e1d4 --- /dev/null +++ b/@ether/library/Language/Piet/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec npiet "$@" diff --git a/@ether/library/Language/Pkl/check.sh b/@ether/library/Language/Pkl/check.sh new file mode 100755 index 00000000..cd41232f --- /dev/null +++ b/@ether/library/Language/Pkl/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v pkl >/dev/null 2>&1 diff --git a/@ether/library/Language/Pkl/install.sh b/@ether/library/Language/Pkl/install.sh new file mode 100755 index 00000000..85cd6603 --- /dev/null +++ b/@ether/library/Language/Pkl/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Pkl from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/apple/pkl" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/apple/pkl.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./gradlew build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install pkl +elif command -v nix >/dev/null 2>&1; then + nix profile install nixpkgs#pkl +else + echo "Download Pkl from https://pkl-lang.org/main/current/pkl-cli/index.html#installation" >&2 + echo "Or use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Pkl/repl.sh b/@ether/library/Language/Pkl/repl.sh new file mode 100755 index 00000000..5a35ceea --- /dev/null +++ b/@ether/library/Language/Pkl/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec pkl repl diff --git a/@ether/library/Language/Pkl/run.sh b/@ether/library/Language/Pkl/run.sh new file mode 100755 index 00000000..b6555e2c --- /dev/null +++ b/@ether/library/Language/Pkl/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec pkl eval "$@" diff --git a/@ether/library/Language/PlantUML/check.sh b/@ether/library/Language/PlantUML/check.sh new file mode 100755 index 00000000..49a2c2d9 --- /dev/null +++ b/@ether/library/Language/PlantUML/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v plantuml >/dev/null 2>&1 diff --git a/@ether/library/Language/PlantUML/install.sh b/@ether/library/Language/PlantUML/install.sh new file mode 100755 index 00000000..7cd5e5b7 --- /dev/null +++ b/@ether/library/Language/PlantUML/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing PlantUML from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/plantuml/plantuml" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/plantuml/plantuml.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./gradlew build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install plantuml +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y plantuml +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y plantuml +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm plantuml +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/PlantUML/repl.sh b/@ether/library/Language/PlantUML/repl.sh new file mode 100755 index 00000000..03bfdf53 --- /dev/null +++ b/@ether/library/Language/PlantUML/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "PlantUML does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/PlantUML/run.sh b/@ether/library/Language/PlantUML/run.sh new file mode 100755 index 00000000..d3a931bc --- /dev/null +++ b/@ether/library/Language/PlantUML/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec plantuml "$@" diff --git a/@ether/library/Language/Plutus/check.sh b/@ether/library/Language/Plutus/check.sh new file mode 100755 index 00000000..f2fae6dc --- /dev/null +++ b/@ether/library/Language/Plutus/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v plutus >/dev/null 2>&1 || (command -v cabal >/dev/null 2>&1 && command -v ghc >/dev/null 2>&1) diff --git a/@ether/library/Language/Plutus/install.sh b/@ether/library/Language/Plutus/install.sh new file mode 100755 index 00000000..17ddcdf4 --- /dev/null +++ b/@ether/library/Language/Plutus/install.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail +# Plutus: Cardano smart contract language - https://plutus.cardano.intersectmbo.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/IntersectMBO/plutus" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/IntersectMBO/plutus.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cabal build all + exit 0 +fi +# Plutus requires GHC and Cabal +if ! command -v ghc >/dev/null 2>&1; then + echo "GHC is required. Install via ghcup: curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh" >&2 + exit 1 +fi +if ! command -v cabal >/dev/null 2>&1; then + echo "Cabal is required. Install via ghcup: ghcup install cabal" >&2 + exit 1 +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/IntersectMBO/plutus" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/IntersectMBO/plutus.git "$REPO_DIR" +fi +cd "$REPO_DIR" && cabal build all diff --git a/@ether/library/Language/Plutus/packages.sh b/@ether/library/Language/Plutus/packages.sh new file mode 100755 index 00000000..5ee03488 --- /dev/null +++ b/@ether/library/Language/Plutus/packages.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Plutus" +REGISTRIES=( + "Hackage (Haskell ecosystem): https://hackage.haskell.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Note: Plutus uses the Haskell/Cabal ecosystem." + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v cabal &>/dev/null; then + cabal list "$@" + else + echo "Visit: https://hackage.haskell.org/packages/search?terms=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://hackage.haskell.org/package/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to your .cabal file build-depends:" + echo " build-depends: $1" + echo "" + echo "Then run: cabal build" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Plutus/repl.sh b/@ether/library/Language/Plutus/repl.sh new file mode 100755 index 00000000..a4244811 --- /dev/null +++ b/@ether/library/Language/Plutus/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Use cabal repl within a Plutus project." >&2 +exit 1 diff --git a/@ether/library/Language/Plutus/run.sh b/@ether/library/Language/Plutus/run.sh new file mode 100755 index 00000000..6e76529b --- /dev/null +++ b/@ether/library/Language/Plutus/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Plutus runs within the Cardano ecosystem. Use cabal run within a Plutus project." >&2 +exit 1 diff --git a/@ether/library/Language/Pony/check.sh b/@ether/library/Language/Pony/check.sh new file mode 100755 index 00000000..d1c9b4fd --- /dev/null +++ b/@ether/library/Language/Pony/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v ponyc >/dev/null 2>&1 diff --git a/@ether/library/Language/Pony/install.sh b/@ether/library/Language/Pony/install.sh new file mode 100755 index 00000000..e5ca5bc2 --- /dev/null +++ b/@ether/library/Language/Pony/install.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Pony from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ponylang/ponyc" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ponylang/ponyc.git "$REPO_DIR" + fi + cd "$REPO_DIR" + make -j"$(nproc)" + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install ponyc +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E04F0923 2>/dev/null || true + echo "deb https://dl.cloudsmith.io/public/ponylang/releases/deb/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ponylang.list + sudo apt-get update && sudo apt-get install -y ponyc +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y ponyc || { + echo "Use --from-source for Fedora." >&2; exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm ponyc +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Pony/repl.sh b/@ether/library/Language/Pony/repl.sh new file mode 100755 index 00000000..af294b23 --- /dev/null +++ b/@ether/library/Language/Pony/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Pony does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Pony/run.sh b/@ether/library/Language/Pony/run.sh new file mode 100755 index 00000000..1a47b3d7 --- /dev/null +++ b/@ether/library/Language/Pony/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +DIR="$(dirname "$1")" +ponyc "$DIR" +exec "$DIR/$(basename "$DIR")" diff --git a/@ether/library/Language/PostCSS/check.sh b/@ether/library/Language/PostCSS/check.sh new file mode 100755 index 00000000..dc5082a4 --- /dev/null +++ b/@ether/library/Language/PostCSS/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v postcss >/dev/null 2>&1 diff --git a/@ether/library/Language/PostCSS/install.sh b/@ether/library/Language/PostCSS/install.sh new file mode 100755 index 00000000..55eeec5a --- /dev/null +++ b/@ether/library/Language/PostCSS/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing PostCSS from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/postcss/postcss" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/postcss/postcss.git "$REPO_DIR" + fi + cd "$REPO_DIR" + npm install + exit 0 +fi +npm install -g postcss postcss-cli diff --git a/@ether/library/Language/PostCSS/repl.sh b/@ether/library/Language/PostCSS/repl.sh new file mode 100755 index 00000000..60bc702b --- /dev/null +++ b/@ether/library/Language/PostCSS/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "PostCSS does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/PostCSS/run.sh b/@ether/library/Language/PostCSS/run.sh new file mode 100755 index 00000000..40022be4 --- /dev/null +++ b/@ether/library/Language/PostCSS/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec postcss "$@" diff --git a/@ether/library/Language/PostScript/check.sh b/@ether/library/Language/PostScript/check.sh new file mode 100755 index 00000000..402279f2 --- /dev/null +++ b/@ether/library/Language/PostScript/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v gs >/dev/null 2>&1 diff --git a/@ether/library/Language/PostScript/install.sh b/@ether/library/Language/PostScript/install.sh new file mode 100755 index 00000000..45d53874 --- /dev/null +++ b/@ether/library/Language/PostScript/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# PostScript - Ghostscript interpreter +if [[ "$(uname)" == "Darwin" ]]; then + brew install ghostscript +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y ghostscript +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y ghostscript +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm ghostscript +else + echo "Unsupported package manager. Please install Ghostscript manually." >&2; exit 1 +fi diff --git a/@ether/library/Language/PostScript/packages.sh b/@ether/library/Language/PostScript/packages.sh new file mode 100755 index 00000000..83b55113 --- /dev/null +++ b/@ether/library/Language/PostScript/packages.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "PostScript does not have a package manager." diff --git a/@ether/library/Language/PostScript/repl.sh b/@ether/library/Language/PostScript/repl.sh new file mode 100755 index 00000000..d0339cd2 --- /dev/null +++ b/@ether/library/Language/PostScript/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gs diff --git a/@ether/library/Language/PostScript/run.sh b/@ether/library/Language/PostScript/run.sh new file mode 100755 index 00000000..6d9c152e --- /dev/null +++ b/@ether/library/Language/PostScript/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gs "$@" diff --git a/@ether/library/Language/PowerShell/check.sh b/@ether/library/Language/PowerShell/check.sh new file mode 100755 index 00000000..e1e0796b --- /dev/null +++ b/@ether/library/Language/PowerShell/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v pwsh >/dev/null 2>&1 diff --git a/@ether/library/Language/PowerShell/install.sh b/@ether/library/Language/PowerShell/install.sh new file mode 100755 index 00000000..d1149af0 --- /dev/null +++ b/@ether/library/Language/PowerShell/install.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing PowerShell from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/PowerShell/PowerShell" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/PowerShell/PowerShell.git "$REPO_DIR" + fi + cd "$REPO_DIR" + dotnet build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install powershell/tap/powershell +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y wget apt-transport-https software-properties-common + source /etc/os-release + wget -q "https://packages.microsoft.com/config/ubuntu/$VERSION_ID/packages-microsoft-prod.deb" + sudo dpkg -i packages-microsoft-prod.deb + rm packages-microsoft-prod.deb + sudo apt-get update && sudo apt-get install -y powershell +elif command -v dnf >/dev/null 2>&1; then + sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc + sudo dnf install -y powershell +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm powershell-bin 2>/dev/null || { + echo "Install powershell-bin from AUR." >&2; exit 1 + } +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/PowerShell/repl.sh b/@ether/library/Language/PowerShell/repl.sh new file mode 100755 index 00000000..9581cd94 --- /dev/null +++ b/@ether/library/Language/PowerShell/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec pwsh diff --git a/@ether/library/Language/PowerShell/run.sh b/@ether/library/Language/PowerShell/run.sh new file mode 100755 index 00000000..6263722d --- /dev/null +++ b/@ether/library/Language/PowerShell/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec pwsh -File "$@" diff --git a/@ether/library/Language/ProBT/check.sh b/@ether/library/Language/ProBT/check.sh new file mode 100755 index 00000000..c644986b --- /dev/null +++ b/@ether/library/Language/ProBT/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "ProBT is commercial software; no standard check available." >&2 +exit 1 diff --git a/@ether/library/Language/ProBT/install.sh b/@ether/library/Language/ProBT/install.sh new file mode 100755 index 00000000..82c2b535 --- /dev/null +++ b/@ether/library/Language/ProBT/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "ProBT is commercial software. Visit https://www.bayesia.com/probt for installation." >&2 +echo "No automated installer available." >&2 +exit 1 diff --git a/@ether/library/Language/ProBT/repl.sh b/@ether/library/Language/ProBT/repl.sh new file mode 100755 index 00000000..5308d51c --- /dev/null +++ b/@ether/library/Language/ProBT/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "ProBT does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ProBT/run.sh b/@ether/library/Language/ProBT/run.sh new file mode 100755 index 00000000..18b9be7f --- /dev/null +++ b/@ether/library/Language/ProBT/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "ProBT is commercial software; no standard runner available." >&2 +exit 1 diff --git a/@ether/library/Language/ProbCog/check.sh b/@ether/library/Language/ProbCog/check.sh new file mode 100755 index 00000000..e4be9f5e --- /dev/null +++ b/@ether/library/Language/ProbCog/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import probcog" >/dev/null 2>&1 diff --git a/@ether/library/Language/ProbCog/install.sh b/@ether/library/Language/ProbCog/install.sh new file mode 100755 index 00000000..a27a936d --- /dev/null +++ b/@ether/library/Language/ProbCog/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/opcode81/ProbCog" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/opcode81/ProbCog.git "$REPO_DIR" +fi +cd "$REPO_DIR" +python3 -m pip install . diff --git a/@ether/library/Language/ProbCog/repl.sh b/@ether/library/Language/ProbCog/repl.sh new file mode 100755 index 00000000..7e1f5310 --- /dev/null +++ b/@ether/library/Language/ProbCog/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "ProbCog does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ProbCog/run.sh b/@ether/library/Language/ProbCog/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/ProbCog/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/ProbLog/check.sh b/@ether/library/Language/ProbLog/check.sh new file mode 100755 index 00000000..8f5ccfd6 --- /dev/null +++ b/@ether/library/Language/ProbLog/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v problog >/dev/null 2>&1 diff --git a/@ether/library/Language/ProbLog/install.sh b/@ether/library/Language/ProbLog/install.sh new file mode 100755 index 00000000..b059c7ac --- /dev/null +++ b/@ether/library/Language/ProbLog/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +pip install problog diff --git a/@ether/library/Language/ProbLog/repl.sh b/@ether/library/Language/ProbLog/repl.sh new file mode 100755 index 00000000..4c5606ed --- /dev/null +++ b/@ether/library/Language/ProbLog/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "ProbLog does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ProbLog/run.sh b/@ether/library/Language/ProbLog/run.sh new file mode 100755 index 00000000..429fe4df --- /dev/null +++ b/@ether/library/Language/ProbLog/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec problog "$1" diff --git a/@ether/library/Language/ProbabilisticC/check.sh b/@ether/library/Language/ProbabilisticC/check.sh new file mode 100755 index 00000000..9294f13e --- /dev/null +++ b/@ether/library/Language/ProbabilisticC/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v gcc >/dev/null 2>&1 || command -v clang >/dev/null 2>&1 diff --git a/@ether/library/Language/ProbabilisticC/install.sh b/@ether/library/Language/ProbabilisticC/install.sh new file mode 100755 index 00000000..5eeb1881 --- /dev/null +++ b/@ether/library/Language/ProbabilisticC/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Probabilistic-C is a research language described in:" +echo " https://web.stanford.edu/~ngoodman/papers/RHG-aisb.pdf" +echo "No public distribution is available. Install a C compiler as the base requirement." +if [[ "$(uname)" == "Darwin" ]]; then + xcode-select --install 2>/dev/null || true +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gcc +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gcc +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gcc +fi diff --git a/@ether/library/Language/ProbabilisticC/repl.sh b/@ether/library/Language/ProbabilisticC/repl.sh new file mode 100755 index 00000000..46f498f7 --- /dev/null +++ b/@ether/library/Language/ProbabilisticC/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Probabilistic-C does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ProbabilisticC/run.sh b/@ether/library/Language/ProbabilisticC/run.sh new file mode 100755 index 00000000..7ce8ee6f --- /dev/null +++ b/@ether/library/Language/ProbabilisticC/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +INPUT="$1"; shift +OUT="$(mktemp)" +gcc -o "$OUT" "$INPUT" -lm "$@" +"$OUT" +rm -f "$OUT" diff --git a/@ether/library/Language/Processing/check.sh b/@ether/library/Language/Processing/check.sh new file mode 100755 index 00000000..85a972ee --- /dev/null +++ b/@ether/library/Language/Processing/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v processing-java >/dev/null 2>&1 diff --git a/@ether/library/Language/Processing/install.sh b/@ether/library/Language/Processing/install.sh new file mode 100755 index 00000000..a0dd7c25 --- /dev/null +++ b/@ether/library/Language/Processing/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask processing +elif command -v apt-get >/dev/null 2>&1; then + echo "Download Processing from https://processing.org/download" >&2 + echo "Or install processing-java via:" >&2 + curl -fsSL https://processing.org/download -o /tmp/processing.tgz + tar -xzf /tmp/processing.tgz -C "$HOME/.local/share/" && rm -f /tmp/processing.tgz + ln -sf "$HOME/.local/share/processing-"*/processing-java "$HOME/.local/bin/processing-java" +else + echo "Download Processing from https://processing.org/download" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Processing/repl.sh b/@ether/library/Language/Processing/repl.sh new file mode 100755 index 00000000..fc83acdb --- /dev/null +++ b/@ether/library/Language/Processing/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Processing does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Processing/run.sh b/@ether/library/Language/Processing/run.sh new file mode 100755 index 00000000..8fea2f87 --- /dev/null +++ b/@ether/library/Language/Processing/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec processing-java --sketch="$(dirname "$1")" --run diff --git a/@ether/library/Language/Prolog/check.sh b/@ether/library/Language/Prolog/check.sh new file mode 100755 index 00000000..ca0e125d --- /dev/null +++ b/@ether/library/Language/Prolog/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v swipl >/dev/null 2>&1 diff --git a/@ether/library/Language/Prolog/install.sh b/@ether/library/Language/Prolog/install.sh new file mode 100755 index 00000000..0a33fb38 --- /dev/null +++ b/@ether/library/Language/Prolog/install.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail +# Prolog - SWI-Prolog +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing SWI-Prolog from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/SWI-Prolog/swipl-devel" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone --recurse-submodules https://github.com/SWI-Prolog/swipl-devel.git "$REPO_DIR" + fi + cd "$REPO_DIR" + mkdir -p build && cd build + cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local + make -j"$(nproc)" + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install swi-prolog +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y swi-prolog +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y swipl +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm swi-prolog +else + echo "Unsupported package manager. Use --from-source or visit https://www.swi-prolog.org/download/stable" >&2; exit 1 +fi diff --git a/@ether/library/Language/Prolog/packages.sh b/@ether/library/Language/Prolog/packages.sh new file mode 100755 index 00000000..18626159 --- /dev/null +++ b/@ether/library/Language/Prolog/packages.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://www.swi-prolog.org/pack/list" + +usage() { + echo "Prolog Package Manager (SWI-Prolog Pack System)" + echo "" + echo "Registry: $REGISTRY" + echo "" + echo "Usage: packages.sh [args]" + echo "" + echo "Commands:" + echo " search Search for packs" + echo " info Show pack information" + echo " install Install a pack" +} + +cmd_search() { + local query="$1" + if command -v swipl &>/dev/null; then + swipl -g "pack_search('$query'), halt" 2>/dev/null || echo "Visit: $REGISTRY?p=$query" + else + echo "swipl not found. Search online:" + echo " $REGISTRY?p=$query" + fi +} + +cmd_info() { + local pack="$1" + echo "Pack info: $REGISTRY?p=$pack" +} + +cmd_install() { + local pack="$1" + if command -v swipl &>/dev/null; then + swipl -g "pack_install('$pack', [interactive(false)]), halt" + else + echo "swipl not found. Install SWI-Prolog first." + exit 1 + fi +} + +case "${1:-}" in + search) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh search "; exit 1; } + cmd_search "$1" + ;; + info) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh info "; exit 1; } + cmd_info "$1" + ;; + install) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh install "; exit 1; } + cmd_install "$1" + ;; + *) + usage + ;; +esac diff --git a/@ether/library/Language/Prolog/repl.sh b/@ether/library/Language/Prolog/repl.sh new file mode 100755 index 00000000..de60d6e4 --- /dev/null +++ b/@ether/library/Language/Prolog/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec swipl diff --git a/@ether/library/Language/Prolog/run.sh b/@ether/library/Language/Prolog/run.sh new file mode 100755 index 00000000..2339a2df --- /dev/null +++ b/@ether/library/Language/Prolog/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec swipl "$@" diff --git a/@ether/library/Language/Promela/check.sh b/@ether/library/Language/Promela/check.sh new file mode 100755 index 00000000..367796e5 --- /dev/null +++ b/@ether/library/Language/Promela/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v spin >/dev/null 2>&1 diff --git a/@ether/library/Language/Promela/install.sh b/@ether/library/Language/Promela/install.sh new file mode 100755 index 00000000..467de016 --- /dev/null +++ b/@ether/library/Language/Promela/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install spin +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y spin +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y spin +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm spin +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Promela/repl.sh b/@ether/library/Language/Promela/repl.sh new file mode 100755 index 00000000..2cf3998c --- /dev/null +++ b/@ether/library/Language/Promela/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Promela/SPIN does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Promela/run.sh b/@ether/library/Language/Promela/run.sh new file mode 100755 index 00000000..435a030f --- /dev/null +++ b/@ether/library/Language/Promela/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec spin "$1" diff --git a/@ether/library/Language/ProtocolBuffers/check.sh b/@ether/library/Language/ProtocolBuffers/check.sh new file mode 100755 index 00000000..1ddc64fa --- /dev/null +++ b/@ether/library/Language/ProtocolBuffers/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v protoc >/dev/null 2>&1 diff --git a/@ether/library/Language/ProtocolBuffers/install.sh b/@ether/library/Language/ProtocolBuffers/install.sh new file mode 100755 index 00000000..14619e49 --- /dev/null +++ b/@ether/library/Language/ProtocolBuffers/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/protocolbuffers/protobuf" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/protocolbuffers/protobuf.git "$REPO_DIR" + fi + cd "$REPO_DIR" + cmake -B build -DCMAKE_INSTALL_PREFIX="$HOME/.local" && cmake --build build -j"$(nproc)" && cmake --install build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install protobuf +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y protobuf-compiler +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y protobuf-compiler +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm protobuf +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/ProtocolBuffers/repl.sh b/@ether/library/Language/ProtocolBuffers/repl.sh new file mode 100755 index 00000000..9694bb0e --- /dev/null +++ b/@ether/library/Language/ProtocolBuffers/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Protocol Buffers does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ProtocolBuffers/run.sh b/@ether/library/Language/ProtocolBuffers/run.sh new file mode 100755 index 00000000..ac801968 --- /dev/null +++ b/@ether/library/Language/ProtocolBuffers/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec protoc "$1" diff --git a/@ether/library/Language/Prover9/check.sh b/@ether/library/Language/Prover9/check.sh new file mode 100755 index 00000000..53d89db3 --- /dev/null +++ b/@ether/library/Language/Prover9/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v prover9 >/dev/null 2>&1 diff --git a/@ether/library/Language/Prover9/install.sh b/@ether/library/Language/Prover9/install.sh new file mode 100755 index 00000000..c0e72603 --- /dev/null +++ b/@ether/library/Language/Prover9/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/theoremprover-museum/prover9" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/theoremprover-museum/prover9.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make all +sudo cp bin/* /usr/local/bin/ || cp bin/* "$HOME/.local/bin/" diff --git a/@ether/library/Language/Prover9/repl.sh b/@ether/library/Language/Prover9/repl.sh new file mode 100755 index 00000000..9b518ec9 --- /dev/null +++ b/@ether/library/Language/Prover9/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Prover9 does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Prover9/run.sh b/@ether/library/Language/Prover9/run.sh new file mode 100755 index 00000000..9f5b8344 --- /dev/null +++ b/@ether/library/Language/Prover9/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec prover9 -f "$1" diff --git a/@ether/library/Language/PureScript/check.sh b/@ether/library/Language/PureScript/check.sh new file mode 100755 index 00000000..b7695d98 --- /dev/null +++ b/@ether/library/Language/PureScript/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v purs >/dev/null 2>&1 diff --git a/@ether/library/Language/PureScript/install.sh b/@ether/library/Language/PureScript/install.sh new file mode 100755 index 00000000..e751577d --- /dev/null +++ b/@ether/library/Language/PureScript/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/purescript/purescript" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/purescript/purescript.git "$REPO_DIR" + fi + cd "$REPO_DIR" + stack build && stack install + exit 0 +fi +npm install -g purescript spago diff --git a/@ether/library/Language/PureScript/packages.sh b/@ether/library/Language/PureScript/packages.sh new file mode 100755 index 00000000..e6fb351b --- /dev/null +++ b/@ether/library/Language/PureScript/packages.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="PureScript" +REGISTRIES=( + "Pursuit: https://pursuit.purescript.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://pursuit.purescript.org/search?q=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://pursuit.purescript.org/packages/purescript-$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + spago install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/PureScript/repl.sh b/@ether/library/Language/PureScript/repl.sh new file mode 100755 index 00000000..d78994e0 --- /dev/null +++ b/@ether/library/Language/PureScript/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec spago repl diff --git a/@ether/library/Language/PureScript/run.sh b/@ether/library/Language/PureScript/run.sh new file mode 100755 index 00000000..7d3a9024 --- /dev/null +++ b/@ether/library/Language/PureScript/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec spago run --main "$1" diff --git a/@ether/library/Language/PyMC/check.sh b/@ether/library/Language/PyMC/check.sh new file mode 100755 index 00000000..e89a08df --- /dev/null +++ b/@ether/library/Language/PyMC/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import pymc" >/dev/null 2>&1 diff --git a/@ether/library/Language/PyMC/install.sh b/@ether/library/Language/PyMC/install.sh new file mode 100755 index 00000000..ef344079 --- /dev/null +++ b/@ether/library/Language/PyMC/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +pip install pymc diff --git a/@ether/library/Language/PyMC/repl.sh b/@ether/library/Language/PyMC/repl.sh new file mode 100755 index 00000000..ec828435 --- /dev/null +++ b/@ether/library/Language/PyMC/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 diff --git a/@ether/library/Language/PyMC/run.sh b/@ether/library/Language/PyMC/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/PyMC/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/PyQuil/check.sh b/@ether/library/Language/PyQuil/check.sh new file mode 100755 index 00000000..594a8c0c --- /dev/null +++ b/@ether/library/Language/PyQuil/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import pyquil" >/dev/null 2>&1 diff --git a/@ether/library/Language/PyQuil/install.sh b/@ether/library/Language/PyQuil/install.sh new file mode 100755 index 00000000..29a1fa90 --- /dev/null +++ b/@ether/library/Language/PyQuil/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +pip install pyquil diff --git a/@ether/library/Language/PyQuil/repl.sh b/@ether/library/Language/PyQuil/repl.sh new file mode 100755 index 00000000..ec828435 --- /dev/null +++ b/@ether/library/Language/PyQuil/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 diff --git a/@ether/library/Language/PyQuil/run.sh b/@ether/library/Language/PyQuil/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/PyQuil/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/PyTorch/check.sh b/@ether/library/Language/PyTorch/check.sh new file mode 100755 index 00000000..23ef24be --- /dev/null +++ b/@ether/library/Language/PyTorch/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import torch" >/dev/null 2>&1 diff --git a/@ether/library/Language/PyTorch/install.sh b/@ether/library/Language/PyTorch/install.sh new file mode 100755 index 00000000..cea011d5 --- /dev/null +++ b/@ether/library/Language/PyTorch/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +pip install torch torchvision torchaudio diff --git a/@ether/library/Language/PyTorch/repl.sh b/@ether/library/Language/PyTorch/repl.sh new file mode 100755 index 00000000..ec828435 --- /dev/null +++ b/@ether/library/Language/PyTorch/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 diff --git a/@ether/library/Language/PyTorch/run.sh b/@ether/library/Language/PyTorch/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/PyTorch/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/PyZX/check.sh b/@ether/library/Language/PyZX/check.sh new file mode 100755 index 00000000..428b4674 --- /dev/null +++ b/@ether/library/Language/PyZX/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import pyzx" >/dev/null 2>&1 diff --git a/@ether/library/Language/PyZX/install.sh b/@ether/library/Language/PyZX/install.sh new file mode 100755 index 00000000..9cf1a7b7 --- /dev/null +++ b/@ether/library/Language/PyZX/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +pip install pyzx diff --git a/@ether/library/Language/PyZX/repl.sh b/@ether/library/Language/PyZX/repl.sh new file mode 100755 index 00000000..ec828435 --- /dev/null +++ b/@ether/library/Language/PyZX/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 diff --git a/@ether/library/Language/PyZX/run.sh b/@ether/library/Language/PyZX/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/PyZX/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Pyret/check.sh b/@ether/library/Language/Pyret/check.sh new file mode 100755 index 00000000..42e5ffeb --- /dev/null +++ b/@ether/library/Language/Pyret/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/brownplt/pyret-lang" +[[ -d "$REPO_DIR" ]] && command -v node >/dev/null 2>&1 diff --git a/@ether/library/Language/Pyret/install.sh b/@ether/library/Language/Pyret/install.sh new file mode 100755 index 00000000..ee6e15e2 --- /dev/null +++ b/@ether/library/Language/Pyret/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/brownplt/pyret-lang" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/brownplt/pyret-lang.git "$REPO_DIR" +fi +cd "$REPO_DIR" +npm install +npm run build diff --git a/@ether/library/Language/Pyret/repl.sh b/@ether/library/Language/Pyret/repl.sh new file mode 100755 index 00000000..cf4dadec --- /dev/null +++ b/@ether/library/Language/Pyret/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Pyret does not provide a CLI REPL. Use https://code.pyret.org/" >&2 +exit 1 diff --git a/@ether/library/Language/Pyret/run.sh b/@ether/library/Language/Pyret/run.sh new file mode 100755 index 00000000..6f4465ea --- /dev/null +++ b/@ether/library/Language/Pyret/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/brownplt/pyret-lang" +exec node "$REPO_DIR/build/phaseA/pyret.jarr" --run "$1" diff --git a/@ether/library/Language/Pyro/check.sh b/@ether/library/Language/Pyro/check.sh new file mode 100755 index 00000000..6b51eb53 --- /dev/null +++ b/@ether/library/Language/Pyro/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import pyro" >/dev/null 2>&1 diff --git a/@ether/library/Language/Pyro/install.sh b/@ether/library/Language/Pyro/install.sh new file mode 100755 index 00000000..c7b438a1 --- /dev/null +++ b/@ether/library/Language/Pyro/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +pip install pyro-ppl diff --git a/@ether/library/Language/Pyro/repl.sh b/@ether/library/Language/Pyro/repl.sh new file mode 100755 index 00000000..ec828435 --- /dev/null +++ b/@ether/library/Language/Pyro/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 diff --git a/@ether/library/Language/Pyro/run.sh b/@ether/library/Language/Pyro/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/Pyro/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Python/check.sh b/@ether/library/Language/Python/check.sh new file mode 100755 index 00000000..2fe182ef --- /dev/null +++ b/@ether/library/Language/Python/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v python3 >/dev/null 2>&1 diff --git a/@ether/library/Language/Python/install.sh b/@ether/library/Language/Python/install.sh new file mode 100755 index 00000000..289eec1a --- /dev/null +++ b/@ether/library/Language/Python/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Python from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/python/cpython" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/python/cpython.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./configure --prefix="$HOME/.local" && make -j"$(nproc)" && make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install python3 +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y python3 python3-pip python3-venv +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y python3 python3-pip +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm python python-pip +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Python/packages.sh b/@ether/library/Language/Python/packages.sh new file mode 100755 index 00000000..fe0d3edf --- /dev/null +++ b/@ether/library/Language/Python/packages.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Python" +REGISTRIES=( + "PyPI: https://pypi.org" + "Anaconda: https://anaconda.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + pip index versions "$1" 2>/dev/null || echo "Visit: https://pypi.org/search/?q=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + pip show "$1" 2>/dev/null || pip index versions "$1" 2>/dev/null || echo "Visit: https://pypi.org/project/$1/" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + pip install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Python/repl.sh b/@ether/library/Language/Python/repl.sh new file mode 100755 index 00000000..0a639985 --- /dev/null +++ b/@ether/library/Language/Python/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 diff --git a/@ether/library/Language/Python/run.sh b/@ether/library/Language/Python/run.sh new file mode 100755 index 00000000..ba668b95 --- /dev/null +++ b/@ether/library/Language/Python/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 "$@" diff --git a/@ether/library/Language/QSharp/check.sh b/@ether/library/Language/QSharp/check.sh new file mode 100755 index 00000000..0928a5c1 --- /dev/null +++ b/@ether/library/Language/QSharp/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import qsharp" >/dev/null 2>&1 diff --git a/@ether/library/Language/QSharp/install.sh b/@ether/library/Language/QSharp/install.sh new file mode 100755 index 00000000..11bf6121 --- /dev/null +++ b/@ether/library/Language/QSharp/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/microsoft/qsharp" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/microsoft/qsharp.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install . + exit 0 +fi +pip install qsharp diff --git a/@ether/library/Language/QSharp/repl.sh b/@ether/library/Language/QSharp/repl.sh new file mode 100755 index 00000000..b5d99fb8 --- /dev/null +++ b/@ether/library/Language/QSharp/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import qsharp; qsharp.init(); import code; code.interact(local={'qsharp': qsharp})" diff --git a/@ether/library/Language/QSharp/run.sh b/@ether/library/Language/QSharp/run.sh new file mode 100755 index 00000000..f51a901a --- /dev/null +++ b/@ether/library/Language/QSharp/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c " +import qsharp +qsharp.eval(open('$1').read()) +" diff --git a/@ether/library/Language/Qt/check.sh b/@ether/library/Language/Qt/check.sh new file mode 100755 index 00000000..c6e3ddc4 --- /dev/null +++ b/@ether/library/Language/Qt/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v qmake >/dev/null 2>&1 diff --git a/@ether/library/Language/Qt/install.sh b/@ether/library/Language/Qt/install.sh new file mode 100755 index 00000000..9db4e86f --- /dev/null +++ b/@ether/library/Language/Qt/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install qt +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y qt5-qtbase-devel +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm qt5-base +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Qt/repl.sh b/@ether/library/Language/Qt/repl.sh new file mode 100755 index 00000000..1637da7d --- /dev/null +++ b/@ether/library/Language/Qt/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Qt does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Qt/run.sh b/@ether/library/Language/Qt/run.sh new file mode 100755 index 00000000..3873cec4 --- /dev/null +++ b/@ether/library/Language/Qt/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Qt is a framework, not a script runner. Use qmake to build projects." >&2 +exit 1 diff --git a/@ether/library/Language/Quantomatic/check.sh b/@ether/library/Language/Quantomatic/check.sh new file mode 100755 index 00000000..46478b3e --- /dev/null +++ b/@ether/library/Language/Quantomatic/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zxcalc/quantomatic" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/Quantomatic/install.sh b/@ether/library/Language/Quantomatic/install.sh new file mode 100755 index 00000000..2d43e73d --- /dev/null +++ b/@ether/library/Language/Quantomatic/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zxcalc/quantomatic" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/zxcalc/quantomatic.git "$REPO_DIR" +fi +cd "$REPO_DIR" +./build.sh diff --git a/@ether/library/Language/Quantomatic/repl.sh b/@ether/library/Language/Quantomatic/repl.sh new file mode 100755 index 00000000..835ba6ad --- /dev/null +++ b/@ether/library/Language/Quantomatic/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Quantomatic does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Quantomatic/run.sh b/@ether/library/Language/Quantomatic/run.sh new file mode 100755 index 00000000..0265739f --- /dev/null +++ b/@ether/library/Language/Quantomatic/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zxcalc/quantomatic" +exec java -jar "$REPO_DIR/gui/dist/quantomatic.jar" "$1" diff --git a/@ether/library/Language/QuiZX/check.sh b/@ether/library/Language/QuiZX/check.sh new file mode 100755 index 00000000..2bc36fd6 --- /dev/null +++ b/@ether/library/Language/QuiZX/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zxcalc/quizx" +[[ -d "$REPO_DIR" ]] && command -v cargo >/dev/null 2>&1 diff --git a/@ether/library/Language/QuiZX/install.sh b/@ether/library/Language/QuiZX/install.sh new file mode 100755 index 00000000..e3182d47 --- /dev/null +++ b/@ether/library/Language/QuiZX/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zxcalc/quizx" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/zxcalc/quizx.git "$REPO_DIR" +fi +cd "$REPO_DIR" +cargo build --release diff --git a/@ether/library/Language/QuiZX/repl.sh b/@ether/library/Language/QuiZX/repl.sh new file mode 100755 index 00000000..3563bdb7 --- /dev/null +++ b/@ether/library/Language/QuiZX/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "QuiZX does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/QuiZX/run.sh b/@ether/library/Language/QuiZX/run.sh new file mode 100755 index 00000000..628f89f1 --- /dev/null +++ b/@ether/library/Language/QuiZX/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zxcalc/quizx" +cd "$REPO_DIR" +exec cargo run --release -- "$1" diff --git a/@ether/library/Language/Quil/check.sh b/@ether/library/Language/Quil/check.sh new file mode 100755 index 00000000..594a8c0c --- /dev/null +++ b/@ether/library/Language/Quil/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import pyquil" >/dev/null 2>&1 diff --git a/@ether/library/Language/Quil/install.sh b/@ether/library/Language/Quil/install.sh new file mode 100755 index 00000000..3b3d6589 --- /dev/null +++ b/@ether/library/Language/Quil/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# Quil is a quantum instruction language spec; programs are run via PyQuil +pip install pyquil diff --git a/@ether/library/Language/Quil/repl.sh b/@ether/library/Language/Quil/repl.sh new file mode 100755 index 00000000..79d1bfe1 --- /dev/null +++ b/@ether/library/Language/Quil/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Quil does not provide an interactive REPL. Use PyQuil via Python." >&2 +exit 1 diff --git a/@ether/library/Language/Quil/run.sh b/@ether/library/Language/Quil/run.sh new file mode 100755 index 00000000..cc1cf28e --- /dev/null +++ b/@ether/library/Language/Quil/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c " +from pyquil import Program +from pyquil.quilbase import DefGate +prog = Program() +prog += open('$1').read() +print(prog) +" diff --git a/@ether/library/Language/Quipper/check.sh b/@ether/library/Language/Quipper/check.sh new file mode 100755 index 00000000..ca5887c4 --- /dev/null +++ b/@ether/library/Language/Quipper/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/thephoeron/quipper-language" +[[ -d "$REPO_DIR" ]] && command -v ghc >/dev/null 2>&1 diff --git a/@ether/library/Language/Quipper/install.sh b/@ether/library/Language/Quipper/install.sh new file mode 100755 index 00000000..08973e64 --- /dev/null +++ b/@ether/library/Language/Quipper/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/thephoeron/quipper-language" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/thephoeron/quipper-language.git "$REPO_DIR" +fi +cd "$REPO_DIR" +cabal update && cabal install diff --git a/@ether/library/Language/Quipper/repl.sh b/@ether/library/Language/Quipper/repl.sh new file mode 100755 index 00000000..9f7d2488 --- /dev/null +++ b/@ether/library/Language/Quipper/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ghci -package quipper diff --git a/@ether/library/Language/Quipper/run.sh b/@ether/library/Language/Quipper/run.sh new file mode 100755 index 00000000..cde1783e --- /dev/null +++ b/@ether/library/Language/Quipper/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec runhaskell "$1" diff --git a/@ether/library/Language/R/check.sh b/@ether/library/Language/R/check.sh new file mode 100755 index 00000000..1857b5cf --- /dev/null +++ b/@ether/library/Language/R/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v Rscript >/dev/null 2>&1 diff --git a/@ether/library/Language/R/install.sh b/@ether/library/Language/R/install.sh new file mode 100755 index 00000000..4fb9c1e0 --- /dev/null +++ b/@ether/library/Language/R/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install r +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y r-base +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y R +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm r +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/R/packages.sh b/@ether/library/Language/R/packages.sh new file mode 100755 index 00000000..9b6e1fb6 --- /dev/null +++ b/@ether/library/Language/R/packages.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="R" +REGISTRIES=( + "CRAN: https://cran.r-project.org" + "Bioconductor: https://bioconductor.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://cran.r-project.org/web/packages/available_packages_by_name.html" + echo "Search: https://www.r-pkg.org/search?q=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v Rscript &>/dev/null; then + Rscript -e "packageDescription(\"$1\")" 2>/dev/null || echo "Visit: https://cran.r-project.org/package=$1" + else + echo "Visit: https://cran.r-project.org/package=$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + Rscript -e "install.packages(\"$1\", repos='https://cloud.r-project.org')" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/R/repl.sh b/@ether/library/Language/R/repl.sh new file mode 100755 index 00000000..98eeca1e --- /dev/null +++ b/@ether/library/Language/R/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec R diff --git a/@ether/library/Language/R/run.sh b/@ether/library/Language/R/run.sh new file mode 100755 index 00000000..81226edb --- /dev/null +++ b/@ether/library/Language/R/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec Rscript "$1" diff --git a/@ether/library/Language/RISCVAssembly/check.sh b/@ether/library/Language/RISCVAssembly/check.sh new file mode 100755 index 00000000..56e1c059 --- /dev/null +++ b/@ether/library/Language/RISCVAssembly/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v riscv64-linux-gnu-as >/dev/null 2>&1 || command -v riscv64-unknown-elf-as >/dev/null 2>&1 diff --git a/@ether/library/Language/RISCVAssembly/install.sh b/@ether/library/Language/RISCVAssembly/install.sh new file mode 100755 index 00000000..9d5d15b1 --- /dev/null +++ b/@ether/library/Language/RISCVAssembly/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew tap riscv-software-src/riscv + brew install riscv-tools +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu qemu-user +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu qemu-user +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm riscv64-linux-gnu-gcc riscv64-linux-gnu-binutils qemu-user +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/RISCVAssembly/repl.sh b/@ether/library/Language/RISCVAssembly/repl.sh new file mode 100755 index 00000000..7236a4dc --- /dev/null +++ b/@ether/library/Language/RISCVAssembly/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "RISC-V Assembly does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/RISCVAssembly/run.sh b/@ether/library/Language/RISCVAssembly/run.sh new file mode 100755 index 00000000..5b52ccd7 --- /dev/null +++ b/@ether/library/Language/RISCVAssembly/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +AS=riscv64-linux-gnu-as +LD=riscv64-linux-gnu-ld +command -v "$AS" >/dev/null 2>&1 || { AS=riscv64-unknown-elf-as; LD=riscv64-unknown-elf-ld; } +TMPDIR=$(mktemp -d) +"$AS" -o "$TMPDIR/out.o" "$1" +"$LD" -o "$TMPDIR/out" "$TMPDIR/out.o" +exec qemu-riscv64 "$TMPDIR/out" diff --git a/@ether/library/Language/Racket/check.sh b/@ether/library/Language/Racket/check.sh new file mode 100755 index 00000000..c44ea772 --- /dev/null +++ b/@ether/library/Language/Racket/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v racket >/dev/null 2>&1 diff --git a/@ether/library/Language/Racket/install.sh b/@ether/library/Language/Racket/install.sh new file mode 100755 index 00000000..3e5a0b68 --- /dev/null +++ b/@ether/library/Language/Racket/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/racket/racket" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/racket/racket.git "$REPO_DIR" + fi + cd "$REPO_DIR" + make && sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask racket +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y racket +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y racket +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm racket +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Racket/packages.sh b/@ether/library/Language/Racket/packages.sh new file mode 100755 index 00000000..99364bb0 --- /dev/null +++ b/@ether/library/Language/Racket/packages.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Racket" +REGISTRIES=( + "Racket Packages: https://pkgs.racket-lang.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v raco &>/dev/null; then + raco pkg search "$@" 2>/dev/null || echo "Visit: https://pkgs.racket-lang.org/search?q=$1" + else + echo "Visit: https://pkgs.racket-lang.org/search?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://pkgs.racket-lang.org/package/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + raco pkg install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Racket/repl.sh b/@ether/library/Language/Racket/repl.sh new file mode 100755 index 00000000..b7c17ba1 --- /dev/null +++ b/@ether/library/Language/Racket/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec racket diff --git a/@ether/library/Language/Racket/run.sh b/@ether/library/Language/Racket/run.sh new file mode 100755 index 00000000..c5cc48f2 --- /dev/null +++ b/@ether/library/Language/Racket/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec racket "$1" diff --git a/@ether/library/Language/Rainier/check.sh b/@ether/library/Language/Rainier/check.sh new file mode 100755 index 00000000..dd5dea99 --- /dev/null +++ b/@ether/library/Language/Rainier/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/stripe/rainier" +[[ -d "$REPO_DIR" ]] && command -v sbt >/dev/null 2>&1 diff --git a/@ether/library/Language/Rainier/install.sh b/@ether/library/Language/Rainier/install.sh new file mode 100755 index 00000000..934431f3 --- /dev/null +++ b/@ether/library/Language/Rainier/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/stripe/rainier" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/stripe/rainier.git "$REPO_DIR" +fi +cd "$REPO_DIR" +sbt publishLocal diff --git a/@ether/library/Language/Rainier/repl.sh b/@ether/library/Language/Rainier/repl.sh new file mode 100755 index 00000000..415512b3 --- /dev/null +++ b/@ether/library/Language/Rainier/repl.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/stripe/rainier" +cd "$REPO_DIR" +exec sbt console diff --git a/@ether/library/Language/Rainier/run.sh b/@ether/library/Language/Rainier/run.sh new file mode 100755 index 00000000..83cd34c1 --- /dev/null +++ b/@ether/library/Language/Rainier/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec scala "$1" diff --git a/@ether/library/Language/Raku/check.sh b/@ether/library/Language/Raku/check.sh new file mode 100755 index 00000000..0705ceaa --- /dev/null +++ b/@ether/library/Language/Raku/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v raku >/dev/null 2>&1 || command -v rakudo >/dev/null 2>&1 diff --git a/@ether/library/Language/Raku/install.sh b/@ether/library/Language/Raku/install.sh new file mode 100755 index 00000000..5a301a0d --- /dev/null +++ b/@ether/library/Language/Raku/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +# Raku (formerly Perl 6) - Rakudo +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Rakudo from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/rakudo/rakudo" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/rakudo/rakudo.git "$REPO_DIR" + fi + cd "$REPO_DIR" + perl Configure.pl --gen-moar --gen-nqp --backends=moar + make -j"$(nproc)" + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install rakudo +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y rakudo +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y rakudo +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm rakudo +else + echo "Unsupported package manager. Use --from-source or visit https://rakudo.org/downloads" >&2; exit 1 +fi diff --git a/@ether/library/Language/Raku/packages.sh b/@ether/library/Language/Raku/packages.sh new file mode 100755 index 00000000..433d9a7a --- /dev/null +++ b/@ether/library/Language/Raku/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Raku" +REGISTRIES=( + "Raku Land: https://raku.land" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v zef &>/dev/null; then + zef search "$@" + else + echo "Visit: https://raku.land/?q=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v zef &>/dev/null; then + zef info "$1" + else + echo "Visit: https://raku.land/zef:$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + zef install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Raku/repl.sh b/@ether/library/Language/Raku/repl.sh new file mode 100755 index 00000000..8836529d --- /dev/null +++ b/@ether/library/Language/Raku/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec raku diff --git a/@ether/library/Language/Raku/run.sh b/@ether/library/Language/Raku/run.sh new file mode 100755 index 00000000..7da1975d --- /dev/null +++ b/@ether/library/Language/Raku/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec raku "$@" diff --git a/@ether/library/Language/RankPL/check.sh b/@ether/library/Language/RankPL/check.sh new file mode 100755 index 00000000..4d0a3945 --- /dev/null +++ b/@ether/library/Language/RankPL/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/tjitze/RankPL" +[[ -d "$REPO_DIR" ]] && command -v java >/dev/null 2>&1 diff --git a/@ether/library/Language/RankPL/install.sh b/@ether/library/Language/RankPL/install.sh new file mode 100755 index 00000000..a1bca458 --- /dev/null +++ b/@ether/library/Language/RankPL/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/tjitze/RankPL" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/tjitze/RankPL.git "$REPO_DIR" +fi +cd "$REPO_DIR" +mvn package -DskipTests diff --git a/@ether/library/Language/RankPL/repl.sh b/@ether/library/Language/RankPL/repl.sh new file mode 100755 index 00000000..ab14e6d5 --- /dev/null +++ b/@ether/library/Language/RankPL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "RankPL does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/RankPL/run.sh b/@ether/library/Language/RankPL/run.sh new file mode 100755 index 00000000..7d7d6d08 --- /dev/null +++ b/@ether/library/Language/RankPL/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/tjitze/RankPL" +exec java -jar "$REPO_DIR/target/RankPL.jar" "$1" diff --git a/@ether/library/Language/ReScript/check.sh b/@ether/library/Language/ReScript/check.sh new file mode 100755 index 00000000..95d2eb95 --- /dev/null +++ b/@ether/library/Language/ReScript/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v rescript >/dev/null 2>&1 diff --git a/@ether/library/Language/ReScript/install.sh b/@ether/library/Language/ReScript/install.sh new file mode 100755 index 00000000..0727f947 --- /dev/null +++ b/@ether/library/Language/ReScript/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/rescript-lang/rescript-compiler" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/rescript-lang/rescript-compiler.git "$REPO_DIR" + fi + cd "$REPO_DIR" + npm install && npm run build + exit 0 +fi +npm install -g rescript diff --git a/@ether/library/Language/ReScript/repl.sh b/@ether/library/Language/ReScript/repl.sh new file mode 100755 index 00000000..5ef4aaaf --- /dev/null +++ b/@ether/library/Language/ReScript/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "ReScript does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ReScript/run.sh b/@ether/library/Language/ReScript/run.sh new file mode 100755 index 00000000..1ca4dc4f --- /dev/null +++ b/@ether/library/Language/ReScript/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec rescript build && node "$1" diff --git a/@ether/library/Language/ReactiveX/check.sh b/@ether/library/Language/ReactiveX/check.sh new file mode 100755 index 00000000..697e8687 --- /dev/null +++ b/@ether/library/Language/ReactiveX/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import reactivex" >/dev/null 2>&1 diff --git a/@ether/library/Language/ReactiveX/install.sh b/@ether/library/Language/ReactiveX/install.sh new file mode 100755 index 00000000..6b6f8380 --- /dev/null +++ b/@ether/library/Language/ReactiveX/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "ReactiveX is a specification with implementations in many languages." >&2 +echo "Install a specific implementation: RxJava, RxJS, RxPY, etc." >&2 +echo "For Python: pip install rx" >&2 +pip install reactivex diff --git a/@ether/library/Language/ReactiveX/repl.sh b/@ether/library/Language/ReactiveX/repl.sh new file mode 100755 index 00000000..ec828435 --- /dev/null +++ b/@ether/library/Language/ReactiveX/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 diff --git a/@ether/library/Language/ReactiveX/run.sh b/@ether/library/Language/ReactiveX/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/ReactiveX/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/Reason/check.sh b/@ether/library/Language/Reason/check.sh new file mode 100755 index 00000000..c3a64d19 --- /dev/null +++ b/@ether/library/Language/Reason/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v bsc >/dev/null 2>&1 || command -v refmt >/dev/null 2>&1 diff --git a/@ether/library/Language/Reason/install.sh b/@ether/library/Language/Reason/install.sh new file mode 100755 index 00000000..f66fe06d --- /dev/null +++ b/@ether/library/Language/Reason/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/reasonml/reason" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/reasonml/reason.git "$REPO_DIR" + fi + cd "$REPO_DIR" + opam pin add reason . -y + exit 0 +fi +npm install -g bs-platform diff --git a/@ether/library/Language/Reason/repl.sh b/@ether/library/Language/Reason/repl.sh new file mode 100755 index 00000000..8cbdbf8a --- /dev/null +++ b/@ether/library/Language/Reason/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Reason does not provide a standalone REPL. Use rtop via opam or the online playground." >&2 +exit 1 diff --git a/@ether/library/Language/Reason/run.sh b/@ether/library/Language/Reason/run.sh new file mode 100755 index 00000000..36404860 --- /dev/null +++ b/@ether/library/Language/Reason/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec bsc "$1" diff --git a/@ether/library/Language/Rebol/check.sh b/@ether/library/Language/Rebol/check.sh new file mode 100755 index 00000000..2f7e1edb --- /dev/null +++ b/@ether/library/Language/Rebol/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v rebol >/dev/null 2>&1 || command -v r3 >/dev/null 2>&1 diff --git a/@ether/library/Language/Rebol/install.sh b/@ether/library/Language/Rebol/install.sh new file mode 100755 index 00000000..d0a4fbcc --- /dev/null +++ b/@ether/library/Language/Rebol/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +# Rebol / Red +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Rebol 3 (Ren-C) from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/metaeducation/ren-c" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/metaeducation/ren-c.git "$REPO_DIR" + fi + cd "$REPO_DIR" + make -j"$(nproc)" + sudo cp build/r3 /usr/local/bin/r3 + exit 0 +fi +echo "Rebol is not available via standard package managers." +echo "Download Rebol 2: http://www.rebol.com/download.html" +echo "Download Rebol 3 (Ren-C): https://github.com/metaeducation/ren-c/releases" +echo "" +echo "After downloading, place the binary in your PATH." >&2 +exit 1 diff --git a/@ether/library/Language/Rebol/packages.sh b/@ether/library/Language/Rebol/packages.sh new file mode 100755 index 00000000..cf13745e --- /dev/null +++ b/@ether/library/Language/Rebol/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Rebol does not have a standard package manager." +echo "See: http://www.rebol.org/view-tools.r" diff --git a/@ether/library/Language/Rebol/repl.sh b/@ether/library/Language/Rebol/repl.sh new file mode 100755 index 00000000..a3808172 --- /dev/null +++ b/@ether/library/Language/Rebol/repl.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v r3 >/dev/null 2>&1; then + exec r3 +elif command -v rebol >/dev/null 2>&1; then + exec rebol +else + echo "Neither r3 nor rebol found in PATH." >&2; exit 1 +fi diff --git a/@ether/library/Language/Rebol/run.sh b/@ether/library/Language/Rebol/run.sh new file mode 100755 index 00000000..4a1ef9f3 --- /dev/null +++ b/@ether/library/Language/Rebol/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v r3 >/dev/null 2>&1; then + exec r3 "$@" +elif command -v rebol >/dev/null 2>&1; then + exec rebol --script "$@" +else + echo "Neither r3 nor rebol found in PATH." >&2; exit 1 +fi diff --git a/@ether/library/Language/Red/check.sh b/@ether/library/Language/Red/check.sh new file mode 100755 index 00000000..7309ba8e --- /dev/null +++ b/@ether/library/Language/Red/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v red >/dev/null 2>&1 diff --git a/@ether/library/Language/Red/install.sh b/@ether/library/Language/Red/install.sh new file mode 100755 index 00000000..ab1942f6 --- /dev/null +++ b/@ether/library/Language/Red/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/red/red" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/red/red.git "$REPO_DIR" + fi + cd "$REPO_DIR" + echo "Build Red from source per instructions at https://www.red-lang.org/p/getting-started.html" >&2 + exit 0 +fi +# Download pre-built binary +ARCH=$(uname -m) +if [[ "$(uname)" == "Linux" ]]; then + curl -fsSL https://static.red-lang.org/dl/auto/linux/red-latest -o /tmp/red + chmod +x /tmp/red + sudo cp /tmp/red /usr/local/bin/red || cp /tmp/red "$HOME/.local/bin/red" +elif [[ "$(uname)" == "Darwin" ]]; then + curl -fsSL https://static.red-lang.org/dl/auto/mac/red-latest -o /tmp/red + chmod +x /tmp/red + sudo cp /tmp/red /usr/local/bin/red || cp /tmp/red "$HOME/.local/bin/red" +else + echo "Unsupported platform." >&2; exit 1 +fi diff --git a/@ether/library/Language/Red/repl.sh b/@ether/library/Language/Red/repl.sh new file mode 100755 index 00000000..e5847118 --- /dev/null +++ b/@ether/library/Language/Red/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec red diff --git a/@ether/library/Language/Red/run.sh b/@ether/library/Language/Red/run.sh new file mode 100755 index 00000000..a2195835 --- /dev/null +++ b/@ether/library/Language/Red/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec red "$1" diff --git a/@ether/library/Language/Rhombus/check.sh b/@ether/library/Language/Rhombus/check.sh new file mode 100755 index 00000000..c44ea772 --- /dev/null +++ b/@ether/library/Language/Rhombus/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v racket >/dev/null 2>&1 diff --git a/@ether/library/Language/Rhombus/install.sh b/@ether/library/Language/Rhombus/install.sh new file mode 100755 index 00000000..f9205a17 --- /dev/null +++ b/@ether/library/Language/Rhombus/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Rhombus is part of Racket; install Racket to use Rhombus +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask racket +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y racket +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y racket +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm racket +else + echo "Unsupported package manager." >&2; exit 1 +fi +raco pkg install --auto rhombus || true diff --git a/@ether/library/Language/Rhombus/repl.sh b/@ether/library/Language/Rhombus/repl.sh new file mode 100755 index 00000000..59fb9bd1 --- /dev/null +++ b/@ether/library/Language/Rhombus/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec racket -I rhombus diff --git a/@ether/library/Language/Rhombus/run.sh b/@ether/library/Language/Rhombus/run.sh new file mode 100755 index 00000000..c5cc48f2 --- /dev/null +++ b/@ether/library/Language/Rhombus/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec racket "$1" diff --git a/@ether/library/Language/Ro/check.sh b/@ether/library/Language/Ro/check.sh new file mode 100755 index 00000000..23c8a1a8 --- /dev/null +++ b/@ether/library/Language/Ro/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/chiragbharadwaj/ro" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/Ro/install.sh b/@ether/library/Language/Ro/install.sh new file mode 100755 index 00000000..f87a4360 --- /dev/null +++ b/@ether/library/Language/Ro/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/chiragbharadwaj/ro" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/chiragbharadwaj/ro.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make diff --git a/@ether/library/Language/Ro/repl.sh b/@ether/library/Language/Ro/repl.sh new file mode 100755 index 00000000..2e639162 --- /dev/null +++ b/@ether/library/Language/Ro/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Ro does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Ro/run.sh b/@ether/library/Language/Ro/run.sh new file mode 100755 index 00000000..5ca490d8 --- /dev/null +++ b/@ether/library/Language/Ro/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/chiragbharadwaj/ro" +exec "$REPO_DIR/ro" "$1" diff --git a/@ether/library/Language/Roc/check.sh b/@ether/library/Language/Roc/check.sh new file mode 100755 index 00000000..e266df59 --- /dev/null +++ b/@ether/library/Language/Roc/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v roc >/dev/null 2>&1 diff --git a/@ether/library/Language/Roc/install.sh b/@ether/library/Language/Roc/install.sh new file mode 100755 index 00000000..cfcd2632 --- /dev/null +++ b/@ether/library/Language/Roc/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/roc-lang/roc" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/roc-lang/roc.git "$REPO_DIR" + fi + cd "$REPO_DIR" + cargo build --release + sudo cp target/release/roc /usr/local/bin/ || cp target/release/roc "$HOME/.local/bin/" + exit 0 +fi +# Official install via nightly release +ARCH=$(uname -m) +OS=$(uname -s | tr '[:upper:]' '[:lower:]') +if [[ "$OS" == "darwin" ]]; then + curl -fsSL "https://github.com/roc-lang/roc/releases/latest/download/roc-nightly-macos_${ARCH}.tar.gz" | tar xz -C /tmp +else + curl -fsSL "https://github.com/roc-lang/roc/releases/latest/download/roc-nightly-linux_${ARCH}.tar.gz" | tar xz -C /tmp +fi +sudo cp /tmp/roc_nightly*/roc /usr/local/bin/ || cp /tmp/roc_nightly*/roc "$HOME/.local/bin/" diff --git a/@ether/library/Language/Roc/repl.sh b/@ether/library/Language/Roc/repl.sh new file mode 100755 index 00000000..ed986b1d --- /dev/null +++ b/@ether/library/Language/Roc/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec roc repl diff --git a/@ether/library/Language/Roc/run.sh b/@ether/library/Language/Roc/run.sh new file mode 100755 index 00000000..c89cf900 --- /dev/null +++ b/@ether/library/Language/Roc/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec roc run "$1" diff --git a/@ether/library/Language/Rockstar/check.sh b/@ether/library/Language/Rockstar/check.sh new file mode 100755 index 00000000..4fc6fb4b --- /dev/null +++ b/@ether/library/Language/Rockstar/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/RockstarLang/rockstar" +[[ -d "$REPO_DIR" ]] && command -v node >/dev/null 2>&1 diff --git a/@ether/library/Language/Rockstar/install.sh b/@ether/library/Language/Rockstar/install.sh new file mode 100755 index 00000000..cbee381b --- /dev/null +++ b/@ether/library/Language/Rockstar/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/RockstarLang/rockstar" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/RockstarLang/rockstar.git "$REPO_DIR" +fi +cd "$REPO_DIR" +npm install diff --git a/@ether/library/Language/Rockstar/repl.sh b/@ether/library/Language/Rockstar/repl.sh new file mode 100755 index 00000000..8b06d0be --- /dev/null +++ b/@ether/library/Language/Rockstar/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Rockstar does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Rockstar/run.sh b/@ether/library/Language/Rockstar/run.sh new file mode 100755 index 00000000..dd3cdbca --- /dev/null +++ b/@ether/library/Language/Rockstar/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/RockstarLang/rockstar" +exec node "$REPO_DIR/satrean/rockstar.js" "$1" diff --git a/@ether/library/Language/Rocq/check.sh b/@ether/library/Language/Rocq/check.sh new file mode 100755 index 00000000..613ee48d --- /dev/null +++ b/@ether/library/Language/Rocq/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v coqc >/dev/null 2>&1 diff --git a/@ether/library/Language/Rocq/install.sh b/@ether/library/Language/Rocq/install.sh new file mode 100755 index 00000000..d5171a78 --- /dev/null +++ b/@ether/library/Language/Rocq/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install coq +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y coq +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y coq +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm coq +elif command -v opam >/dev/null 2>&1; then + opam install coq +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Rocq/packages.sh b/@ether/library/Language/Rocq/packages.sh new file mode 100755 index 00000000..eec5a4ad --- /dev/null +++ b/@ether/library/Language/Rocq/packages.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRIES=( + "https://opam.ocaml.org/packages/" + "https://github.com/coq-community" +) + +usage() { + echo "Rocq (Coq) Package Registries:" + for url in "${REGISTRIES[@]}"; do echo " $url"; done + echo + echo "Usage: packages.sh {search|info|install} " +} + +cmd_search() { + local q="$1" + if command -v opam &>/dev/null; then + opam search "coq-$q" + else + echo "https://opam.ocaml.org/packages/?q=coq-$q" + echo "https://github.com/coq-community?q=$q" + fi +} + +cmd_info() { + local pkg="$1" + if command -v opam &>/dev/null; then + opam show "coq-$pkg" + else + echo "https://opam.ocaml.org/packages/coq-$pkg/" + fi +} + +cmd_install() { + local pkg="$1" + if command -v opam &>/dev/null; then + echo "Installing via opam..." + opam install "coq-$pkg" + else + echo "Install opam first, then run:" + echo " opam install coq-$pkg" + echo + echo "Or browse: https://opam.ocaml.org/packages/coq-$pkg/" + fi +} + +case "${1:-}" in + search) shift; cmd_search "$1" ;; + info) shift; cmd_info "$1" ;; + install) shift; cmd_install "$1" ;; + *) usage ;; +esac diff --git a/@ether/library/Language/Rocq/repl.sh b/@ether/library/Language/Rocq/repl.sh new file mode 100755 index 00000000..bf11dd3c --- /dev/null +++ b/@ether/library/Language/Rocq/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec coqtop diff --git a/@ether/library/Language/Rocq/run.sh b/@ether/library/Language/Rocq/run.sh new file mode 100755 index 00000000..b6f11261 --- /dev/null +++ b/@ether/library/Language/Rocq/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec coqc "$@" diff --git a/@ether/library/Language/Rosette/check.sh b/@ether/library/Language/Rosette/check.sh new file mode 100755 index 00000000..04f5a090 --- /dev/null +++ b/@ether/library/Language/Rosette/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v racket >/dev/null 2>&1 && racket -e '(require rosette)' >/dev/null 2>&1 diff --git a/@ether/library/Language/Rosette/install.sh b/@ether/library/Language/Rosette/install.sh new file mode 100755 index 00000000..6ae6a5fc --- /dev/null +++ b/@ether/library/Language/Rosette/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Rosette requires Racket +if ! command -v racket >/dev/null 2>&1; then + if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask racket + elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y racket + elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y racket + elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm racket + fi +fi +raco pkg install --auto rosette diff --git a/@ether/library/Language/Rosette/repl.sh b/@ether/library/Language/Rosette/repl.sh new file mode 100755 index 00000000..4ac37441 --- /dev/null +++ b/@ether/library/Language/Rosette/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec racket -I rosette diff --git a/@ether/library/Language/Rosette/run.sh b/@ether/library/Language/Rosette/run.sh new file mode 100755 index 00000000..c5cc48f2 --- /dev/null +++ b/@ether/library/Language/Rosette/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec racket "$1" diff --git a/@ether/library/Language/Ruby/check.sh b/@ether/library/Language/Ruby/check.sh new file mode 100755 index 00000000..59386908 --- /dev/null +++ b/@ether/library/Language/Ruby/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v ruby >/dev/null 2>&1 diff --git a/@ether/library/Language/Ruby/install.sh b/@ether/library/Language/Ruby/install.sh new file mode 100755 index 00000000..57bde371 --- /dev/null +++ b/@ether/library/Language/Ruby/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ruby/ruby" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ruby/ruby.git "$REPO_DIR" + fi + cd "$REPO_DIR" && autoconf && ./configure --prefix="$HOME/.local" && make -j"$(nproc)" && make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install ruby +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y ruby ruby-dev +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y ruby ruby-devel +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm ruby +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Ruby/packages.sh b/@ether/library/Language/Ruby/packages.sh new file mode 100755 index 00000000..df4e2ea1 --- /dev/null +++ b/@ether/library/Language/Ruby/packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Ruby" +REGISTRIES=( + "RubyGems: https://rubygems.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v gem &>/dev/null; then + gem search "$@" + else + echo "Visit: https://rubygems.org/search?query=$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v gem &>/dev/null; then + gem info "$1" + else + echo "Visit: https://rubygems.org/gems/$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + gem install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Ruby/repl.sh b/@ether/library/Language/Ruby/repl.sh new file mode 100755 index 00000000..af5d74da --- /dev/null +++ b/@ether/library/Language/Ruby/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec irb diff --git a/@ether/library/Language/Ruby/run.sh b/@ether/library/Language/Ruby/run.sh new file mode 100755 index 00000000..0d8dfed6 --- /dev/null +++ b/@ether/library/Language/Ruby/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec ruby "$@" diff --git a/@ether/library/Language/Rust/check.sh b/@ether/library/Language/Rust/check.sh new file mode 100755 index 00000000..545776a4 --- /dev/null +++ b/@ether/library/Language/Rust/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v rustc >/dev/null 2>&1 diff --git a/@ether/library/Language/Rust/install.sh b/@ether/library/Language/Rust/install.sh new file mode 100755 index 00000000..af571df0 --- /dev/null +++ b/@ether/library/Language/Rust/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Rust from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/rust-lang/rust" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/rust-lang/rust.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./x.py build && ./x.py install + exit 0 +fi +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y diff --git a/@ether/library/Language/Rust/packages.sh b/@ether/library/Language/Rust/packages.sh new file mode 100755 index 00000000..39c817af --- /dev/null +++ b/@ether/library/Language/Rust/packages.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Rust" +REGISTRIES=( + "crates.io: https://crates.io" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + cargo search "$@" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + cargo search --limit 1 "$1" + echo "Details: https://crates.io/crates/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + cargo install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Rust/repl.sh b/@ether/library/Language/Rust/repl.sh new file mode 100755 index 00000000..de3868cb --- /dev/null +++ b/@ether/library/Language/Rust/repl.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v evcxr >/dev/null 2>&1; then + exec evcxr "$@" +else + echo "No Rust REPL found." + echo "Install evcxr: cargo install evcxr_repl" + exit 1 +fi diff --git a/@ether/library/Language/Rust/run.sh b/@ether/library/Language/Rust/run.sh new file mode 100755 index 00000000..595ce9a2 --- /dev/null +++ b/@ether/library/Language/Rust/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +if [[ -d "$file" ]]; then + cd "$file" && cargo run +else + rustc "$file" -o /tmp/rust_out && /tmp/rust_out +fi diff --git a/@ether/library/Language/RxJS/check.sh b/@ether/library/Language/RxJS/check.sh new file mode 100755 index 00000000..3d36e105 --- /dev/null +++ b/@ether/library/Language/RxJS/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v node >/dev/null 2>&1 && node -e "require('rxjs')" >/dev/null 2>&1 diff --git a/@ether/library/Language/RxJS/install.sh b/@ether/library/Language/RxJS/install.sh new file mode 100755 index 00000000..bf207e92 --- /dev/null +++ b/@ether/library/Language/RxJS/install.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +npm install -g rxjs diff --git a/@ether/library/Language/RxJS/repl.sh b/@ether/library/Language/RxJS/repl.sh new file mode 100755 index 00000000..2f9057a6 --- /dev/null +++ b/@ether/library/Language/RxJS/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec node diff --git a/@ether/library/Language/RxJS/run.sh b/@ether/library/Language/RxJS/run.sh new file mode 100755 index 00000000..f082fff1 --- /dev/null +++ b/@ether/library/Language/RxJS/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec node "$1" diff --git a/@ether/library/Language/RxJava/check.sh b/@ether/library/Language/RxJava/check.sh new file mode 100755 index 00000000..aeb069d7 --- /dev/null +++ b/@ether/library/Language/RxJava/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ReactiveX/RxJava" +[[ -d "$REPO_DIR" ]] && command -v java >/dev/null 2>&1 diff --git a/@ether/library/Language/RxJava/install.sh b/@ether/library/Language/RxJava/install.sh new file mode 100755 index 00000000..45d41f99 --- /dev/null +++ b/@ether/library/Language/RxJava/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ReactiveX/RxJava" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ReactiveX/RxJava.git "$REPO_DIR" +fi +cd "$REPO_DIR" +./gradlew build -x test diff --git a/@ether/library/Language/RxJava/repl.sh b/@ether/library/Language/RxJava/repl.sh new file mode 100755 index 00000000..e101619a --- /dev/null +++ b/@ether/library/Language/RxJava/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec jshell diff --git a/@ether/library/Language/RxJava/run.sh b/@ether/library/Language/RxJava/run.sh new file mode 100755 index 00000000..8e61b678 --- /dev/null +++ b/@ether/library/Language/RxJava/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec java "$1" diff --git a/@ether/library/Language/Rzk/check.sh b/@ether/library/Language/Rzk/check.sh new file mode 100755 index 00000000..4ca7b1db --- /dev/null +++ b/@ether/library/Language/Rzk/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v rzk >/dev/null 2>&1 diff --git a/@ether/library/Language/Rzk/install.sh b/@ether/library/Language/Rzk/install.sh new file mode 100755 index 00000000..9d0b89ff --- /dev/null +++ b/@ether/library/Language/Rzk/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/rzk-lang/rzk" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/rzk-lang/rzk.git "$REPO_DIR" + fi + cd "$REPO_DIR" + stack build && stack install + exit 0 +fi +cabal update && cabal install rzk diff --git a/@ether/library/Language/Rzk/repl.sh b/@ether/library/Language/Rzk/repl.sh new file mode 100755 index 00000000..2231b8b9 --- /dev/null +++ b/@ether/library/Language/Rzk/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Rzk does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Rzk/run.sh b/@ether/library/Language/Rzk/run.sh new file mode 100755 index 00000000..1f2d0e49 --- /dev/null +++ b/@ether/library/Language/Rzk/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec rzk typecheck "$1" diff --git a/@ether/library/Language/SIMULA/check.sh b/@ether/library/Language/SIMULA/check.sh new file mode 100755 index 00000000..3f88f73a --- /dev/null +++ b/@ether/library/Language/SIMULA/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v cim >/dev/null 2>&1 diff --git a/@ether/library/Language/SIMULA/install.sh b/@ether/library/Language/SIMULA/install.sh new file mode 100755 index 00000000..692da9ec --- /dev/null +++ b/@ether/library/Language/SIMULA/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# SIMULA: first object-oriented language - GNU Cim compiler +if [[ "$(uname)" == "Darwin" ]]; then + brew install cim || { + echo "Install GNU Cim manually from https://www.gnu.org/software/cim/" >&2 + exit 1 + } +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y cim +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y cim || { + echo "GNU Cim not in repos; build from source at https://www.gnu.org/software/cim/" >&2 + exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + echo "Install cim from AUR: yay -S cim" >&2 + exit 1 +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/SIMULA/repl.sh b/@ether/library/Language/SIMULA/repl.sh new file mode 100755 index 00000000..6ef30e7a --- /dev/null +++ b/@ether/library/Language/SIMULA/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "SIMULA (cim) does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/SIMULA/run.sh b/@ether/library/Language/SIMULA/run.sh new file mode 100755 index 00000000..2545b2fc --- /dev/null +++ b/@ether/library/Language/SIMULA/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +cim "$file" -o /tmp/simula_out && /tmp/simula_out diff --git a/@ether/library/Language/SL/check.sh b/@ether/library/Language/SL/check.sh new file mode 100755 index 00000000..40a075e3 --- /dev/null +++ b/@ether/library/Language/SL/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v sll >/dev/null 2>&1 diff --git a/@ether/library/Language/SL/install.sh b/@ether/library/Language/SL/install.sh new file mode 100755 index 00000000..05529c0c --- /dev/null +++ b/@ether/library/Language/SL/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# SL language - https://github.com/sl-lang/sll +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/sl-lang/sll" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/sl-lang/sll.git "$REPO_DIR" +fi +cd "$REPO_DIR" && make -j"$(nproc)" || cmake -B build && cmake --build build diff --git a/@ether/library/Language/SL/repl.sh b/@ether/library/Language/SL/repl.sh new file mode 100755 index 00000000..0e780e09 --- /dev/null +++ b/@ether/library/Language/SL/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "SL does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/SL/run.sh b/@ether/library/Language/SL/run.sh new file mode 100755 index 00000000..6b3efa01 --- /dev/null +++ b/@ether/library/Language/SL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sll "$@" diff --git a/@ether/library/Language/SMTLIB/check.sh b/@ether/library/Language/SMTLIB/check.sh new file mode 100755 index 00000000..103a6823 --- /dev/null +++ b/@ether/library/Language/SMTLIB/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v z3 >/dev/null 2>&1 diff --git a/@ether/library/Language/SMTLIB/install.sh b/@ether/library/Language/SMTLIB/install.sh new file mode 100755 index 00000000..45cf081b --- /dev/null +++ b/@ether/library/Language/SMTLIB/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# SMT-LIB: standard format for SMT solvers - https://smt-lib.org/ +# Install Z3 as the reference SMT solver +if [[ "$(uname)" == "Darwin" ]]; then + brew install z3 +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y z3 +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y z3 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm z3 +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/SMTLIB/repl.sh b/@ether/library/Language/SMTLIB/repl.sh new file mode 100755 index 00000000..b800fbe0 --- /dev/null +++ b/@ether/library/Language/SMTLIB/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec z3 -in diff --git a/@ether/library/Language/SMTLIB/run.sh b/@ether/library/Language/SMTLIB/run.sh new file mode 100755 index 00000000..cd5d191b --- /dev/null +++ b/@ether/library/Language/SMTLIB/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec z3 "$@" diff --git a/@ether/library/Language/SPARQL/check.sh b/@ether/library/Language/SPARQL/check.sh new file mode 100755 index 00000000..95a50782 --- /dev/null +++ b/@ether/library/Language/SPARQL/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v arq >/dev/null 2>&1 diff --git a/@ether/library/Language/SPARQL/install.sh b/@ether/library/Language/SPARQL/install.sh new file mode 100755 index 00000000..81051387 --- /dev/null +++ b/@ether/library/Language/SPARQL/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +# SPARQL: RDF query language - uses Apache Jena (arq) +# https://jena.apache.org/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install jena +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y libjena-java || { + # Manual download + JENA_VER="5.0.0" + curl -fSL "https://dlcdn.apache.org/jena/binaries/apache-jena-${JENA_VER}.tar.gz" -o /tmp/jena.tar.gz + sudo tar xzf /tmp/jena.tar.gz -C /opt/ && rm /tmp/jena.tar.gz + sudo ln -sf /opt/apache-jena-${JENA_VER}/bin/arq /usr/local/bin/arq + } +elif command -v pacman >/dev/null 2>&1; then + echo "Install Apache Jena manually from https://jena.apache.org/download/" >&2 + exit 1 +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/SPARQL/repl.sh b/@ether/library/Language/SPARQL/repl.sh new file mode 100755 index 00000000..80b6ec56 --- /dev/null +++ b/@ether/library/Language/SPARQL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +echo "SPARQL does not have a standalone interactive REPL." >&2 +echo "Use: arq --query " >&2 +exit 1 diff --git a/@ether/library/Language/SPARQL/run.sh b/@ether/library/Language/SPARQL/run.sh new file mode 100755 index 00000000..0df2f48c --- /dev/null +++ b/@ether/library/Language/SPARQL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec arq --query "$@" diff --git a/@ether/library/Language/SPASS/check.sh b/@ether/library/Language/SPASS/check.sh new file mode 100755 index 00000000..860d5a29 --- /dev/null +++ b/@ether/library/Language/SPASS/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v SPASS >/dev/null 2>&1 diff --git a/@ether/library/Language/SPASS/install.sh b/@ether/library/Language/SPASS/install.sh new file mode 100755 index 00000000..ad1fc0b1 --- /dev/null +++ b/@ether/library/Language/SPASS/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# SPASS: automated theorem prover - https://www.mpi-inf.mpg.de/departments/automation-of-logic/software/spass-workbench/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install spass || { + echo "Download SPASS from https://www.mpi-inf.mpg.de/departments/automation-of-logic/software/spass-workbench/" >&2 + exit 1 + } +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y spass +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y spass || { + echo "Download SPASS from https://www.mpi-inf.mpg.de/departments/automation-of-logic/software/spass-workbench/" >&2 + exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + echo "Install spass from AUR: yay -S spass" >&2 + exit 1 +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/SPASS/repl.sh b/@ether/library/Language/SPASS/repl.sh new file mode 100755 index 00000000..b2cb6f1a --- /dev/null +++ b/@ether/library/Language/SPASS/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "SPASS does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/SPASS/run.sh b/@ether/library/Language/SPASS/run.sh new file mode 100755 index 00000000..f1a816e5 --- /dev/null +++ b/@ether/library/Language/SPASS/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec SPASS "$@" diff --git a/@ether/library/Language/SQL/check.sh b/@ether/library/Language/SQL/check.sh new file mode 100755 index 00000000..5640831a --- /dev/null +++ b/@ether/library/Language/SQL/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v sqlite3 >/dev/null 2>&1 diff --git a/@ether/library/Language/SQL/install.sh b/@ether/library/Language/SQL/install.sh new file mode 100755 index 00000000..101d45b2 --- /dev/null +++ b/@ether/library/Language/SQL/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# SQL: uses SQLite3 as default engine - https://www.sqlite.org/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install sqlite3 +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y sqlite3 +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y sqlite +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm sqlite +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/SQL/repl.sh b/@ether/library/Language/SQL/repl.sh new file mode 100755 index 00000000..5af8f650 --- /dev/null +++ b/@ether/library/Language/SQL/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec sqlite3 diff --git a/@ether/library/Language/SQL/run.sh b/@ether/library/Language/SQL/run.sh new file mode 100755 index 00000000..801663c9 --- /dev/null +++ b/@ether/library/Language/SQL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sqlite3 < "$@" diff --git a/@ether/library/Language/SageMath/check.sh b/@ether/library/Language/SageMath/check.sh new file mode 100755 index 00000000..99feccfb --- /dev/null +++ b/@ether/library/Language/SageMath/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v sage >/dev/null 2>&1 diff --git a/@ether/library/Language/SageMath/install.sh b/@ether/library/Language/SageMath/install.sh new file mode 100755 index 00000000..4ee59bd4 --- /dev/null +++ b/@ether/library/Language/SageMath/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/sagemath/sage" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/sagemath/sage.git "$REPO_DIR" + fi + cd "$REPO_DIR" + make build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask sage +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y sagemath +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y sagemath +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm sagemath +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/SageMath/repl.sh b/@ether/library/Language/SageMath/repl.sh new file mode 100755 index 00000000..79beaecc --- /dev/null +++ b/@ether/library/Language/SageMath/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sage diff --git a/@ether/library/Language/SageMath/run.sh b/@ether/library/Language/SageMath/run.sh new file mode 100755 index 00000000..9236831a --- /dev/null +++ b/@ether/library/Language/SageMath/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sage "$1" diff --git a/@ether/library/Language/Sass/check.sh b/@ether/library/Language/Sass/check.sh new file mode 100755 index 00000000..17fb1e44 --- /dev/null +++ b/@ether/library/Language/Sass/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v sass >/dev/null 2>&1 diff --git a/@ether/library/Language/Sass/install.sh b/@ether/library/Language/Sass/install.sh new file mode 100755 index 00000000..7b07b1ae --- /dev/null +++ b/@ether/library/Language/Sass/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install sass/sass/sass +elif command -v npm >/dev/null 2>&1; then + npm install -g sass +else + echo "Install Node.js first, then: npm install -g sass" >&2; exit 1 +fi diff --git a/@ether/library/Language/Sass/repl.sh b/@ether/library/Language/Sass/repl.sh new file mode 100755 index 00000000..1b31c830 --- /dev/null +++ b/@ether/library/Language/Sass/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sass --interactive diff --git a/@ether/library/Language/Sass/run.sh b/@ether/library/Language/Sass/run.sh new file mode 100755 index 00000000..7ca81be6 --- /dev/null +++ b/@ether/library/Language/Sass/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sass "$1" diff --git a/@ether/library/Language/Saturn/check.sh b/@ether/library/Language/Saturn/check.sh new file mode 100755 index 00000000..c6374406 --- /dev/null +++ b/@ether/library/Language/Saturn/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/siddhartha-gadgil/Saturn" +[[ -d "$REPO_DIR" ]] && command -v lake >/dev/null 2>&1 diff --git a/@ether/library/Language/Saturn/install.sh b/@ether/library/Language/Saturn/install.sh new file mode 100755 index 00000000..0abc9613 --- /dev/null +++ b/@ether/library/Language/Saturn/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/siddhartha-gadgil/Saturn" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/siddhartha-gadgil/Saturn.git "$REPO_DIR" +fi +cd "$REPO_DIR" +lake build diff --git a/@ether/library/Language/Saturn/repl.sh b/@ether/library/Language/Saturn/repl.sh new file mode 100755 index 00000000..a8ba363c --- /dev/null +++ b/@ether/library/Language/Saturn/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Saturn does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Saturn/run.sh b/@ether/library/Language/Saturn/run.sh new file mode 100755 index 00000000..7dc44cdb --- /dev/null +++ b/@ether/library/Language/Saturn/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/siddhartha-gadgil/Saturn" +cd "$REPO_DIR" +exec lake env lean "$1" diff --git a/@ether/library/Language/Saul/check.sh b/@ether/library/Language/Saul/check.sh new file mode 100755 index 00000000..a8b453a7 --- /dev/null +++ b/@ether/library/Language/Saul/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/CogComp/saul" +[[ -d "$REPO_DIR" ]] && command -v sbt >/dev/null 2>&1 diff --git a/@ether/library/Language/Saul/install.sh b/@ether/library/Language/Saul/install.sh new file mode 100755 index 00000000..d53b198d --- /dev/null +++ b/@ether/library/Language/Saul/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/CogComp/saul" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/CogComp/saul.git "$REPO_DIR" +fi +cd "$REPO_DIR" +sbt compile diff --git a/@ether/library/Language/Saul/repl.sh b/@ether/library/Language/Saul/repl.sh new file mode 100755 index 00000000..0b16ef79 --- /dev/null +++ b/@ether/library/Language/Saul/repl.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/CogComp/saul" +cd "$REPO_DIR" +exec sbt console diff --git a/@ether/library/Language/Saul/run.sh b/@ether/library/Language/Saul/run.sh new file mode 100755 index 00000000..83cd34c1 --- /dev/null +++ b/@ether/library/Language/Saul/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec scala "$1" diff --git a/@ether/library/Language/Scaffold/check.sh b/@ether/library/Language/Scaffold/check.sh new file mode 100755 index 00000000..4bd4d49f --- /dev/null +++ b/@ether/library/Language/Scaffold/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/epiqc/ScaffCC" +[[ -d "$REPO_DIR/build" ]] diff --git a/@ether/library/Language/Scaffold/install.sh b/@ether/library/Language/Scaffold/install.sh new file mode 100755 index 00000000..d8e651cf --- /dev/null +++ b/@ether/library/Language/Scaffold/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/epiqc/ScaffCC" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/epiqc/ScaffCC.git "$REPO_DIR" +fi +cd "$REPO_DIR" +mkdir -p build && cd build +cmake .. && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" diff --git a/@ether/library/Language/Scaffold/repl.sh b/@ether/library/Language/Scaffold/repl.sh new file mode 100755 index 00000000..059c2ffa --- /dev/null +++ b/@ether/library/Language/Scaffold/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Scaffold does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Scaffold/run.sh b/@ether/library/Language/Scaffold/run.sh new file mode 100755 index 00000000..90aa454c --- /dev/null +++ b/@ether/library/Language/Scaffold/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/epiqc/ScaffCC" +exec "$REPO_DIR/scaffold.sh" "$1" diff --git a/@ether/library/Language/Scala/check.sh b/@ether/library/Language/Scala/check.sh new file mode 100755 index 00000000..2b2588f5 --- /dev/null +++ b/@ether/library/Language/Scala/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v scala >/dev/null 2>&1 diff --git a/@ether/library/Language/Scala/install.sh b/@ether/library/Language/Scala/install.sh new file mode 100755 index 00000000..be4ef9b7 --- /dev/null +++ b/@ether/library/Language/Scala/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Official method: Coursier (cs setup) - https://www.scala-lang.org/download/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install coursier/formulas/coursier && cs setup -y +else + ARCH=$(uname -m) + if [[ "$ARCH" == "aarch64" ]]; then + curl -fL https://github.com/coursier/coursier/releases/latest/download/cs-aarch64-pc-linux.gz | gzip -d > /tmp/cs + else + curl -fL https://github.com/coursier/coursier/releases/latest/download/cs-x86_64-pc-linux.gz | gzip -d > /tmp/cs + fi + chmod +x /tmp/cs && /tmp/cs setup -y && rm -f /tmp/cs +fi diff --git a/@ether/library/Language/Scala/packages.sh b/@ether/library/Language/Scala/packages.sh new file mode 100755 index 00000000..b8817a01 --- /dev/null +++ b/@ether/library/Language/Scala/packages.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Scala" +REGISTRIES=( + "Maven Central: https://search.maven.org" + "Scaladex: https://index.scala-lang.org" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://index.scala-lang.org/search?q=$1" + echo "Visit: https://search.maven.org/search?q=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://index.scala-lang.org/search?q=$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to build.sbt:" + echo " libraryDependencies += \"org\" %% \"$1\" % \"version\"" + echo "" + echo "Or search for exact coordinates at: https://index.scala-lang.org/search?q=$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Scala/repl.sh b/@ether/library/Language/Scala/repl.sh new file mode 100755 index 00000000..97797a2a --- /dev/null +++ b/@ether/library/Language/Scala/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec scala diff --git a/@ether/library/Language/Scala/run.sh b/@ether/library/Language/Scala/run.sh new file mode 100755 index 00000000..2e131e6f --- /dev/null +++ b/@ether/library/Language/Scala/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec scala "$@" diff --git a/@ether/library/Language/Scheme/check.sh b/@ether/library/Language/Scheme/check.sh new file mode 100755 index 00000000..267ba747 --- /dev/null +++ b/@ether/library/Language/Scheme/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v mit-scheme >/dev/null 2>&1 || command -v scheme >/dev/null 2>&1 || command -v guile >/dev/null 2>&1 diff --git a/@ether/library/Language/Scheme/install.sh b/@ether/library/Language/Scheme/install.sh new file mode 100755 index 00000000..c4c22e81 --- /dev/null +++ b/@ether/library/Language/Scheme/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install mit-scheme +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y mit-scheme +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y mit-scheme +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm mit-scheme +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Scheme/repl.sh b/@ether/library/Language/Scheme/repl.sh new file mode 100755 index 00000000..b7efbb7a --- /dev/null +++ b/@ether/library/Language/Scheme/repl.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v mit-scheme >/dev/null 2>&1; then + exec mit-scheme +elif command -v scheme >/dev/null 2>&1; then + exec scheme +elif command -v guile >/dev/null 2>&1; then + exec guile +fi diff --git a/@ether/library/Language/Scheme/run.sh b/@ether/library/Language/Scheme/run.sh new file mode 100755 index 00000000..8675d9b4 --- /dev/null +++ b/@ether/library/Language/Scheme/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v mit-scheme >/dev/null 2>&1; then + exec mit-scheme --quiet --load "$1" +elif command -v scheme >/dev/null 2>&1; then + exec scheme --script "$1" +elif command -v guile >/dev/null 2>&1; then + exec guile "$1" +fi diff --git a/@ether/library/Language/SciLab/check.sh b/@ether/library/Language/SciLab/check.sh new file mode 100755 index 00000000..5fa633d4 --- /dev/null +++ b/@ether/library/Language/SciLab/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v scilab-cli >/dev/null 2>&1 || command -v scilab >/dev/null 2>&1 diff --git a/@ether/library/Language/SciLab/install.sh b/@ether/library/Language/SciLab/install.sh new file mode 100755 index 00000000..91e2dad0 --- /dev/null +++ b/@ether/library/Language/SciLab/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask scilab +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y scilab +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y scilab +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm scilab +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/SciLab/repl.sh b/@ether/library/Language/SciLab/repl.sh new file mode 100755 index 00000000..1701edf3 --- /dev/null +++ b/@ether/library/Language/SciLab/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec scilab-cli diff --git a/@ether/library/Language/SciLab/run.sh b/@ether/library/Language/SciLab/run.sh new file mode 100755 index 00000000..30612a98 --- /dev/null +++ b/@ether/library/Language/SciLab/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec scilab-cli -f "$1" diff --git a/@ether/library/Language/Scilla/check.sh b/@ether/library/Language/Scilla/check.sh new file mode 100755 index 00000000..4e16a723 --- /dev/null +++ b/@ether/library/Language/Scilla/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v scilla-checker >/dev/null 2>&1 diff --git a/@ether/library/Language/Scilla/install.sh b/@ether/library/Language/Scilla/install.sh new file mode 100755 index 00000000..c393a029 --- /dev/null +++ b/@ether/library/Language/Scilla/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +# Scilla: smart contract language for Zilliqa - https://scilla-lang.org/ +# Built from source (requires opam/OCaml) +if [[ "$(uname)" == "Darwin" ]]; then + brew install pkg-config libffi openssl boost +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y build-essential pkg-config libffi-dev libssl-dev libboost-all-dev libgmp-dev opam +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gcc gcc-c++ pkg-config libffi-devel openssl-devel boost-devel gmp-devel opam +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm base-devel pkg-config libffi openssl boost gmp opam +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Zilliqa/scilla" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Zilliqa/scilla.git "$REPO_DIR" +fi +cd "$REPO_DIR" +opam init --auto-setup --yes || true +eval "$(opam env)" +make opamdep-ci && make diff --git a/@ether/library/Language/Scilla/repl.sh b/@ether/library/Language/Scilla/repl.sh new file mode 100755 index 00000000..8902ab26 --- /dev/null +++ b/@ether/library/Language/Scilla/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Scilla does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Scilla/run.sh b/@ether/library/Language/Scilla/run.sh new file mode 100755 index 00000000..32656e1b --- /dev/null +++ b/@ether/library/Language/Scilla/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec scilla-checker "$@" diff --git a/@ether/library/Language/ScryerProlog/check.sh b/@ether/library/Language/ScryerProlog/check.sh new file mode 100755 index 00000000..d8e02a79 --- /dev/null +++ b/@ether/library/Language/ScryerProlog/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v scryer-prolog >/dev/null 2>&1 diff --git a/@ether/library/Language/ScryerProlog/install.sh b/@ether/library/Language/ScryerProlog/install.sh new file mode 100755 index 00000000..d7cc881c --- /dev/null +++ b/@ether/library/Language/ScryerProlog/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Scryer Prolog: ISO Prolog in Rust - https://www.scryer.pl/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mthom/scryer-prolog" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/mthom/scryer-prolog.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + cp target/release/scryer-prolog "$HOME/.local/bin/" 2>/dev/null || sudo cp target/release/scryer-prolog /usr/local/bin/ + exit 0 +fi +cargo install scryer-prolog diff --git a/@ether/library/Language/ScryerProlog/repl.sh b/@ether/library/Language/ScryerProlog/repl.sh new file mode 100755 index 00000000..6c439cb2 --- /dev/null +++ b/@ether/library/Language/ScryerProlog/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec scryer-prolog diff --git a/@ether/library/Language/ScryerProlog/run.sh b/@ether/library/Language/ScryerProlog/run.sh new file mode 100755 index 00000000..68ccceb1 --- /dev/null +++ b/@ether/library/Language/ScryerProlog/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec scryer-prolog "$@" diff --git a/@ether/library/Language/Sed/check.sh b/@ether/library/Language/Sed/check.sh new file mode 100755 index 00000000..aafc29d7 --- /dev/null +++ b/@ether/library/Language/Sed/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v sed >/dev/null 2>&1 diff --git a/@ether/library/Language/Sed/install.sh b/@ether/library/Language/Sed/install.sh new file mode 100755 index 00000000..c2537ef1 --- /dev/null +++ b/@ether/library/Language/Sed/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# GNU sed - https://www.gnu.org/software/sed/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install gnu-sed +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y sed +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y sed +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm sed +fi diff --git a/@ether/library/Language/Sed/repl.sh b/@ether/library/Language/Sed/repl.sh new file mode 100755 index 00000000..58581ad2 --- /dev/null +++ b/@ether/library/Language/Sed/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Sed does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Sed/run.sh b/@ether/library/Language/Sed/run.sh new file mode 100755 index 00000000..9ff58a84 --- /dev/null +++ b/@ether/library/Language/Sed/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sed -f "$@" diff --git a/@ether/library/Language/Shakespeare/check.sh b/@ether/library/Language/Shakespeare/check.sh new file mode 100755 index 00000000..5c045732 --- /dev/null +++ b/@ether/library/Language/Shakespeare/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v shakespeare >/dev/null 2>&1 diff --git a/@ether/library/Language/Shakespeare/install.sh b/@ether/library/Language/Shakespeare/install.sh new file mode 100755 index 00000000..06794c05 --- /dev/null +++ b/@ether/library/Language/Shakespeare/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Shakespeare Programming Language - https://github.com/zmbc/shakespearelang +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zmbc/shakespearelang" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/zmbc/shakespearelang.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install shakespearelang diff --git a/@ether/library/Language/Shakespeare/repl.sh b/@ether/library/Language/Shakespeare/repl.sh new file mode 100755 index 00000000..4e4b8f6b --- /dev/null +++ b/@ether/library/Language/Shakespeare/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec shakespeare repl diff --git a/@ether/library/Language/Shakespeare/run.sh b/@ether/library/Language/Shakespeare/run.sh new file mode 100755 index 00000000..0e788406 --- /dev/null +++ b/@ether/library/Language/Shakespeare/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec shakespeare run "$@" diff --git a/@ether/library/Language/Shen/check.sh b/@ether/library/Language/Shen/check.sh new file mode 100755 index 00000000..0596a148 --- /dev/null +++ b/@ether/library/Language/Shen/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v shen >/dev/null 2>&1 || command -v shen-cl >/dev/null 2>&1 diff --git a/@ether/library/Language/Shen/install.sh b/@ether/library/Language/Shen/install.sh new file mode 100755 index 00000000..2c723b9b --- /dev/null +++ b/@ether/library/Language/Shen/install.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +# Shen language - https://shenlanguage.org/ +# ShenRuby, Shen/Scheme, or official Shen/SBCL port +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Shen-Language/shen-cl" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Shen-Language/shen-cl.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make fetch && make + exit 0 +fi +# Install via pre-built SBCL port +if [[ "$(uname)" == "Darwin" ]]; then + brew install sbcl +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y sbcl +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y sbcl +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm sbcl +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Shen-Language/shen-cl" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Shen-Language/shen-cl.git "$REPO_DIR" +fi +cd "$REPO_DIR" && make fetch && make diff --git a/@ether/library/Language/Shen/repl.sh b/@ether/library/Language/Shen/repl.sh new file mode 100755 index 00000000..4a5e8cb5 --- /dev/null +++ b/@ether/library/Language/Shen/repl.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +if command -v shen >/dev/null 2>&1; then + exec shen +else + exec shen-cl +fi diff --git a/@ether/library/Language/Shen/run.sh b/@ether/library/Language/Shen/run.sh new file mode 100755 index 00000000..cb3ad1fd --- /dev/null +++ b/@ether/library/Language/Shen/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v shen >/dev/null 2>&1; then + exec shen "$@" +else + exec shen-cl "$@" +fi diff --git a/@ether/library/Language/Silq/check.sh b/@ether/library/Language/Silq/check.sh new file mode 100755 index 00000000..123b78a9 --- /dev/null +++ b/@ether/library/Language/Silq/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v silq >/dev/null 2>&1 diff --git a/@ether/library/Language/Silq/install.sh b/@ether/library/Language/Silq/install.sh new file mode 100755 index 00000000..9c9f9616 --- /dev/null +++ b/@ether/library/Language/Silq/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Silq: high-level quantum programming language - https://silq.ethz.ch/ +# Requires D compiler (LDC) +if [[ "$(uname)" == "Darwin" ]]; then + brew install ldc dub +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y ldc dub gcc zlib1g-dev +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y ldc dub gcc zlib-devel +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm ldc dub gcc zlib +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/eth-sri/silq" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/eth-sri/silq.git "$REPO_DIR" +fi +cd "$REPO_DIR" && make -j"$(nproc)" diff --git a/@ether/library/Language/Silq/repl.sh b/@ether/library/Language/Silq/repl.sh new file mode 100755 index 00000000..99c85ae6 --- /dev/null +++ b/@ether/library/Language/Silq/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Silq does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Silq/run.sh b/@ether/library/Language/Silq/run.sh new file mode 100755 index 00000000..65d41faf --- /dev/null +++ b/@ether/library/Language/Silq/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec silq "$@" diff --git a/@ether/library/Language/Smalltalk/check.sh b/@ether/library/Language/Smalltalk/check.sh new file mode 100755 index 00000000..43d6ae1a --- /dev/null +++ b/@ether/library/Language/Smalltalk/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v gst >/dev/null 2>&1 diff --git a/@ether/library/Language/Smalltalk/install.sh b/@ether/library/Language/Smalltalk/install.sh new file mode 100755 index 00000000..0b493d77 --- /dev/null +++ b/@ether/library/Language/Smalltalk/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# GNU Smalltalk - https://squeak.org/, https://www.gnu.org/software/smalltalk/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install gnu-smalltalk +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gnu-smalltalk +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gnu-smalltalk +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm gnu-smalltalk +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Smalltalk/repl.sh b/@ether/library/Language/Smalltalk/repl.sh new file mode 100755 index 00000000..d662c057 --- /dev/null +++ b/@ether/library/Language/Smalltalk/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec gst diff --git a/@ether/library/Language/Smalltalk/run.sh b/@ether/library/Language/Smalltalk/run.sh new file mode 100755 index 00000000..fd527b98 --- /dev/null +++ b/@ether/library/Language/Smalltalk/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec gst "$@" diff --git a/@ether/library/Language/Snowman/check.sh b/@ether/library/Language/Snowman/check.sh new file mode 100755 index 00000000..28c7f3e9 --- /dev/null +++ b/@ether/library/Language/Snowman/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v snowman >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/KeyboardFire/snowman-lang" + [[ -x "$REPO_DIR/snowman" ]] +} diff --git a/@ether/library/Language/Snowman/install.sh b/@ether/library/Language/Snowman/install.sh new file mode 100755 index 00000000..3862c7cd --- /dev/null +++ b/@ether/library/Language/Snowman/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# Snowman esoteric language - https://github.com/KeyboardFire/snowman-lang +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/KeyboardFire/snowman-lang" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/KeyboardFire/snowman-lang.git "$REPO_DIR" +fi +cd "$REPO_DIR" && make diff --git a/@ether/library/Language/Snowman/repl.sh b/@ether/library/Language/Snowman/repl.sh new file mode 100755 index 00000000..6c445451 --- /dev/null +++ b/@ether/library/Language/Snowman/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Snowman does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Snowman/run.sh b/@ether/library/Language/Snowman/run.sh new file mode 100755 index 00000000..b3e97511 --- /dev/null +++ b/@ether/library/Language/Snowman/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v snowman >/dev/null 2>&1; then + exec snowman "$@" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/KeyboardFire/snowman-lang" + exec "$REPO_DIR/snowman" "$@" +fi diff --git a/@ether/library/Language/Solidity/check.sh b/@ether/library/Language/Solidity/check.sh new file mode 100755 index 00000000..e0b615e1 --- /dev/null +++ b/@ether/library/Language/Solidity/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v solc >/dev/null 2>&1 diff --git a/@ether/library/Language/Solidity/install.sh b/@ether/library/Language/Solidity/install.sh new file mode 100755 index 00000000..f3a7f7f4 --- /dev/null +++ b/@ether/library/Language/Solidity/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail +# Solidity: Ethereum smart contract language - https://soliditylang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ethereum/solidity" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ethereum/solidity.git "$REPO_DIR" + fi + cd "$REPO_DIR" && mkdir -p build && cd build && cmake .. && make -j"$(nproc)" + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew tap ethereum/ethereum && brew install solidity +elif command -v apt-get >/dev/null 2>&1; then + sudo add-apt-repository -y ppa:ethereum/ethereum 2>/dev/null || true + sudo apt-get update && sudo apt-get install -y solc +elif command -v snap >/dev/null 2>&1; then + sudo snap install solc +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm solidity +else + # Fallback: npm install + npm install -g solc +fi diff --git a/@ether/library/Language/Solidity/repl.sh b/@ether/library/Language/Solidity/repl.sh new file mode 100755 index 00000000..fa3d5b1d --- /dev/null +++ b/@ether/library/Language/Solidity/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Solidity does not have an interactive REPL (use Remix IDE or Hardhat console)." >&2 +exit 1 diff --git a/@ether/library/Language/Solidity/run.sh b/@ether/library/Language/Solidity/run.sh new file mode 100755 index 00000000..f0ab37e7 --- /dev/null +++ b/@ether/library/Language/Solidity/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec solc "$@" diff --git a/@ether/library/Language/Sophia/check.sh b/@ether/library/Language/Sophia/check.sh new file mode 100755 index 00000000..178baa35 --- /dev/null +++ b/@ether/library/Language/Sophia/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v aecli >/dev/null 2>&1 diff --git a/@ether/library/Language/Sophia/install.sh b/@ether/library/Language/Sophia/install.sh new file mode 100755 index 00000000..f82b3191 --- /dev/null +++ b/@ether/library/Language/Sophia/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Sophia: Aeternity blockchain smart contract language - https://docs.aeternity.com/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/aeternity/aesophia" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/aeternity/aesophia.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make + exit 0 +fi +npm install -g @aeternity/aepp-cli-js diff --git a/@ether/library/Language/Sophia/packages.sh b/@ether/library/Language/Sophia/packages.sh new file mode 100755 index 00000000..76bbb591 --- /dev/null +++ b/@ether/library/Language/Sophia/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Sophia does not have a standard package manager." +echo "Aeternity contracts: https://github.com/aeternity" diff --git a/@ether/library/Language/Sophia/repl.sh b/@ether/library/Language/Sophia/repl.sh new file mode 100755 index 00000000..73c2c655 --- /dev/null +++ b/@ether/library/Language/Sophia/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Sophia does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Sophia/run.sh b/@ether/library/Language/Sophia/run.sh new file mode 100755 index 00000000..0583f55e --- /dev/null +++ b/@ether/library/Language/Sophia/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Sophia compiles within the Aeternity ecosystem. Use aecli or the Aeternity SDK." >&2 +exit 1 diff --git a/@ether/library/Language/Souffle/check.sh b/@ether/library/Language/Souffle/check.sh new file mode 100755 index 00000000..893eaefe --- /dev/null +++ b/@ether/library/Language/Souffle/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v souffle >/dev/null 2>&1 diff --git a/@ether/library/Language/Souffle/install.sh b/@ether/library/Language/Souffle/install.sh new file mode 100755 index 00000000..4555d0e0 --- /dev/null +++ b/@ether/library/Language/Souffle/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail +# Souffle: Datalog engine - https://souffle-lang.github.io/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/souffle-lang/souffle" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/souffle-lang/souffle.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cmake -S . -B build && cmake --build build -j"$(nproc)" && sudo cmake --install build + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install souffle-lang/souffle/souffle +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y souffle || { + echo "Add PPA or build from source: https://souffle-lang.github.io/install" >&2 + exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + echo "Install souffle from AUR: yay -S souffle" >&2 + exit 1 +else + echo "Unsupported package manager. Build from source with FROM_SOURCE=true." >&2; exit 1 +fi diff --git a/@ether/library/Language/Souffle/repl.sh b/@ether/library/Language/Souffle/repl.sh new file mode 100755 index 00000000..7f37a903 --- /dev/null +++ b/@ether/library/Language/Souffle/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Souffle does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Souffle/run.sh b/@ether/library/Language/Souffle/run.sh new file mode 100755 index 00000000..d5bf0a71 --- /dev/null +++ b/@ether/library/Language/Souffle/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec souffle "$@" diff --git a/@ether/library/Language/Spade/check.sh b/@ether/library/Language/Spade/check.sh new file mode 100755 index 00000000..a869e7ea --- /dev/null +++ b/@ether/library/Language/Spade/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v swim >/dev/null 2>&1 diff --git a/@ether/library/Language/Spade/install.sh b/@ether/library/Language/Spade/install.sh new file mode 100755 index 00000000..564d6611 --- /dev/null +++ b/@ether/library/Language/Spade/install.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +# Spade: HDL language - https://spade-lang.org/ +# Install via cargo (Rust-based) +if command -v cargo >/dev/null 2>&1; then + cargo install --git https://gitlab.com/spade-lang/spade swim +else + echo "Requires Rust/cargo. Install Rust first." >&2 + exit 1 +fi diff --git a/@ether/library/Language/Spade/repl.sh b/@ether/library/Language/Spade/repl.sh new file mode 100755 index 00000000..c9c990ef --- /dev/null +++ b/@ether/library/Language/Spade/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Spade does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Spade/run.sh b/@ether/library/Language/Spade/run.sh new file mode 100755 index 00000000..e7032474 --- /dev/null +++ b/@ether/library/Language/Spade/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec swim "$@" diff --git a/@ether/library/Language/Sphinx/check.sh b/@ether/library/Language/Sphinx/check.sh new file mode 100755 index 00000000..d44c88d3 --- /dev/null +++ b/@ether/library/Language/Sphinx/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v sphinx-build >/dev/null 2>&1 diff --git a/@ether/library/Language/Sphinx/install.sh b/@ether/library/Language/Sphinx/install.sh new file mode 100755 index 00000000..0072f69d --- /dev/null +++ b/@ether/library/Language/Sphinx/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Sphinx: documentation generator - https://www.sphinx-doc.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/sphinx-doc/sphinx" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/sphinx-doc/sphinx.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install sphinx diff --git a/@ether/library/Language/Sphinx/repl.sh b/@ether/library/Language/Sphinx/repl.sh new file mode 100755 index 00000000..db60cd18 --- /dev/null +++ b/@ether/library/Language/Sphinx/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Sphinx does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Sphinx/run.sh b/@ether/library/Language/Sphinx/run.sh new file mode 100755 index 00000000..fa707349 --- /dev/null +++ b/@ether/library/Language/Sphinx/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sphinx-build "$@" diff --git a/@ether/library/Language/SpinalHDL/check.sh b/@ether/library/Language/SpinalHDL/check.sh new file mode 100755 index 00000000..cdf6e874 --- /dev/null +++ b/@ether/library/Language/SpinalHDL/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v sbt >/dev/null 2>&1 diff --git a/@ether/library/Language/SpinalHDL/install.sh b/@ether/library/Language/SpinalHDL/install.sh new file mode 100755 index 00000000..43198324 --- /dev/null +++ b/@ether/library/Language/SpinalHDL/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# SpinalHDL: Scala-based HDL - https://spinalhdl.github.io/ +# Requires Java + sbt (Scala build tool) +if [[ "$(uname)" == "Darwin" ]]; then + brew install sbt +elif command -v apt-get >/dev/null 2>&1; then + echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | sudo tee /etc/apt/sources.list.d/sbt.list + curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add - + sudo apt-get update && sudo apt-get install -y sbt +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y sbt || { + echo "Install sbt from https://www.scala-sbt.org/download.html" >&2; exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm sbt +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/SpinalHDL/SpinalHDL" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/SpinalHDL/SpinalHDL.git "$REPO_DIR" +fi +cd "$REPO_DIR" && sbt publishLocal diff --git a/@ether/library/Language/SpinalHDL/repl.sh b/@ether/library/Language/SpinalHDL/repl.sh new file mode 100755 index 00000000..853be24f --- /dev/null +++ b/@ether/library/Language/SpinalHDL/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec sbt console diff --git a/@ether/library/Language/SpinalHDL/run.sh b/@ether/library/Language/SpinalHDL/run.sh new file mode 100755 index 00000000..0a75cd0c --- /dev/null +++ b/@ether/library/Language/SpinalHDL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sbt "runMain $@" diff --git a/@ether/library/Language/Spiral/check.sh b/@ether/library/Language/Spiral/check.sh new file mode 100755 index 00000000..e403d1d0 --- /dev/null +++ b/@ether/library/Language/Spiral/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mrakgr/The-Spiral-Language" +[[ -d "$REPO_DIR" ]] && command -v dotnet >/dev/null 2>&1 diff --git a/@ether/library/Language/Spiral/install.sh b/@ether/library/Language/Spiral/install.sh new file mode 100755 index 00000000..7f9f7588 --- /dev/null +++ b/@ether/library/Language/Spiral/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +# Spiral language - https://github.com/mrakgr/The-Spiral-Language +# Requires .NET SDK +if ! command -v dotnet >/dev/null 2>&1; then + if [[ "$(uname)" == "Darwin" ]]; then + brew install dotnet + elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y dotnet-sdk-8.0 + elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y dotnet-sdk-8.0 + elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm dotnet-sdk + fi +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mrakgr/The-Spiral-Language" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/mrakgr/The-Spiral-Language.git "$REPO_DIR" +fi +cd "$REPO_DIR" && dotnet build diff --git a/@ether/library/Language/Spiral/repl.sh b/@ether/library/Language/Spiral/repl.sh new file mode 100755 index 00000000..e098090e --- /dev/null +++ b/@ether/library/Language/Spiral/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Spiral does not have a standalone REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Spiral/run.sh b/@ether/library/Language/Spiral/run.sh new file mode 100755 index 00000000..36f88533 --- /dev/null +++ b/@ether/library/Language/Spiral/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mrakgr/The-Spiral-Language" +exec dotnet run --project "$REPO_DIR" -- "$@" diff --git a/@ether/library/Language/Stan/check.sh b/@ether/library/Language/Stan/check.sh new file mode 100755 index 00000000..38241f92 --- /dev/null +++ b/@ether/library/Language/Stan/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v stanc >/dev/null 2>&1 || python3 -c "import cmdstanpy" 2>/dev/null diff --git a/@ether/library/Language/Stan/install.sh b/@ether/library/Language/Stan/install.sh new file mode 100755 index 00000000..c9336ca2 --- /dev/null +++ b/@ether/library/Language/Stan/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# Stan: statistical modeling - https://mc-stan.org/ +# Install CmdStan (command-line interface) +if [[ "$(uname)" == "Darwin" ]]; then + brew install cmdstan +elif pip install cmdstanpy 2>/dev/null; then + python3 -c "import cmdstanpy; cmdstanpy.install_cmdstan()" +else + pip install cmdstanpy + python3 -c "import cmdstanpy; cmdstanpy.install_cmdstan()" +fi diff --git a/@ether/library/Language/Stan/repl.sh b/@ether/library/Language/Stan/repl.sh new file mode 100755 index 00000000..c5ddfa9b --- /dev/null +++ b/@ether/library/Language/Stan/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Stan does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Stan/run.sh b/@ether/library/Language/Stan/run.sh new file mode 100755 index 00000000..7edc90dd --- /dev/null +++ b/@ether/library/Language/Stan/run.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v stanc >/dev/null 2>&1; then + exec stanc "$@" +else + exec python3 -c " +import cmdstanpy, sys +model = cmdstanpy.CmdStanModel(stan_file=sys.argv[1]) +print(model.exe_info()) +" "$@" +fi diff --git a/@ether/library/Language/StandardML/check.sh b/@ether/library/Language/StandardML/check.sh new file mode 100755 index 00000000..edc42aef --- /dev/null +++ b/@ether/library/Language/StandardML/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v sml >/dev/null 2>&1 diff --git a/@ether/library/Language/StandardML/install.sh b/@ether/library/Language/StandardML/install.sh new file mode 100755 index 00000000..bce681bd --- /dev/null +++ b/@ether/library/Language/StandardML/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Standard ML: SML/NJ - https://www.smlnj.org/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install smlnj +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y smlnj +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y smlnj || { + echo "Download from https://www.smlnj.org/dist/working/" >&2; exit 1 + } +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm smlnj +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/StandardML/repl.sh b/@ether/library/Language/StandardML/repl.sh new file mode 100755 index 00000000..a1a0c6af --- /dev/null +++ b/@ether/library/Language/StandardML/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec sml diff --git a/@ether/library/Language/StandardML/run.sh b/@ether/library/Language/StandardML/run.sh new file mode 100755 index 00000000..68d2a41b --- /dev/null +++ b/@ether/library/Language/StandardML/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec sml "$@" diff --git a/@ether/library/Language/Starlark/check.sh b/@ether/library/Language/Starlark/check.sh new file mode 100755 index 00000000..245d6868 --- /dev/null +++ b/@ether/library/Language/Starlark/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v starlark >/dev/null 2>&1 diff --git a/@ether/library/Language/Starlark/install.sh b/@ether/library/Language/Starlark/install.sh new file mode 100755 index 00000000..924b63aa --- /dev/null +++ b/@ether/library/Language/Starlark/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# Starlark - Python-like configuration language +if command -v go >/dev/null 2>&1; then + go install go.starlark.net/cmd/starlark@latest +else + echo "Go is required. Install Go first: https://go.dev/dl/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Starlark/packages.sh b/@ether/library/Language/Starlark/packages.sh new file mode 100755 index 00000000..a45513e7 --- /dev/null +++ b/@ether/library/Language/Starlark/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Starlark does not have a package manager." +echo "Starlark modules are loaded via load() from local files or Bazel repos." diff --git a/@ether/library/Language/Starlark/repl.sh b/@ether/library/Language/Starlark/repl.sh new file mode 100755 index 00000000..ed59712f --- /dev/null +++ b/@ether/library/Language/Starlark/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec starlark diff --git a/@ether/library/Language/Starlark/run.sh b/@ether/library/Language/Starlark/run.sh new file mode 100755 index 00000000..2a557f7a --- /dev/null +++ b/@ether/library/Language/Starlark/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec starlark "$@" diff --git a/@ether/library/Language/Stylus/check.sh b/@ether/library/Language/Stylus/check.sh new file mode 100755 index 00000000..5a4d1715 --- /dev/null +++ b/@ether/library/Language/Stylus/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v stylus >/dev/null 2>&1 diff --git a/@ether/library/Language/Stylus/install.sh b/@ether/library/Language/Stylus/install.sh new file mode 100755 index 00000000..8026a11f --- /dev/null +++ b/@ether/library/Language/Stylus/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Stylus: CSS preprocessor - https://stylus-lang.com/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/stylus/stylus" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/stylus/stylus.git "$REPO_DIR" + fi + cd "$REPO_DIR" && npm install && npm link + exit 0 +fi +npm install -g stylus diff --git a/@ether/library/Language/Stylus/repl.sh b/@ether/library/Language/Stylus/repl.sh new file mode 100755 index 00000000..b4ea4537 --- /dev/null +++ b/@ether/library/Language/Stylus/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Stylus does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Stylus/run.sh b/@ether/library/Language/Stylus/run.sh new file mode 100755 index 00000000..d8f7426c --- /dev/null +++ b/@ether/library/Language/Stylus/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec stylus "$@" diff --git a/@ether/library/Language/Svelte/check.sh b/@ether/library/Language/Svelte/check.sh new file mode 100755 index 00000000..7786e357 --- /dev/null +++ b/@ether/library/Language/Svelte/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v npx >/dev/null 2>&1 && npx svelte --version >/dev/null 2>&1 || npm list -g svelte >/dev/null 2>&1 diff --git a/@ether/library/Language/Svelte/install.sh b/@ether/library/Language/Svelte/install.sh new file mode 100755 index 00000000..29f7e233 --- /dev/null +++ b/@ether/library/Language/Svelte/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# Svelte: web framework - https://svelte.dev/ +npm install -g svelte diff --git a/@ether/library/Language/Svelte/repl.sh b/@ether/library/Language/Svelte/repl.sh new file mode 100755 index 00000000..f3c2e175 --- /dev/null +++ b/@ether/library/Language/Svelte/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Svelte does not have an interactive REPL (use https://svelte.dev/repl)." >&2 +exit 1 diff --git a/@ether/library/Language/Svelte/run.sh b/@ether/library/Language/Svelte/run.sh new file mode 100755 index 00000000..1f7a2c50 --- /dev/null +++ b/@ether/library/Language/Svelte/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# Svelte files are compiled as part of a project +cat "$@" diff --git a/@ether/library/Language/Sway/check.sh b/@ether/library/Language/Sway/check.sh new file mode 100755 index 00000000..a9d958d5 --- /dev/null +++ b/@ether/library/Language/Sway/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v forc >/dev/null 2>&1 diff --git a/@ether/library/Language/Sway/install.sh b/@ether/library/Language/Sway/install.sh new file mode 100755 index 00000000..2756c7e2 --- /dev/null +++ b/@ether/library/Language/Sway/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Sway: Fuel blockchain smart contract language - https://fuellabs.github.io/sway/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/FuelLabs/sway" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/FuelLabs/sway.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + exit 0 +fi +# Install fuelup (Fuel toolchain manager) which includes forc +curl -fsSL https://install.fuel.network | sh diff --git a/@ether/library/Language/Sway/packages.sh b/@ether/library/Language/Sway/packages.sh new file mode 100755 index 00000000..ae50e11e --- /dev/null +++ b/@ether/library/Language/Sway/packages.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Sway" +REGISTRIES=( + "forc.pub: https://forc.pub" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://forc.pub/?search=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://forc.pub/$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + if command -v forc &>/dev/null; then + forc install "$1" + else + echo "Add to Forc.toml [dependencies]:" + echo " $1 = { git = \"https://github.com/OWNER/$1\", branch = \"master\" }" + echo "" + echo "Then run: forc build" + fi + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Sway/repl.sh b/@ether/library/Language/Sway/repl.sh new file mode 100755 index 00000000..31c31dd1 --- /dev/null +++ b/@ether/library/Language/Sway/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Sway does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Sway/run.sh b/@ether/library/Language/Sway/run.sh new file mode 100755 index 00000000..8ba6a96e --- /dev/null +++ b/@ether/library/Language/Sway/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec forc build "$@" diff --git a/@ether/library/Language/Swift/check.sh b/@ether/library/Language/Swift/check.sh new file mode 100755 index 00000000..c9ff7258 --- /dev/null +++ b/@ether/library/Language/Swift/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v swift >/dev/null 2>&1 diff --git a/@ether/library/Language/Swift/install.sh b/@ether/library/Language/Swift/install.sh new file mode 100755 index 00000000..b3d41b77 --- /dev/null +++ b/@ether/library/Language/Swift/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + # Official swiftly installer (https://www.swift.org/install/macos/) + curl -O https://download.swift.org/swiftly/darwin/swiftly.pkg + installer -pkg swiftly.pkg -target CurrentUserHomeDirectory + ~/.swiftly/bin/swiftly init --quiet-shell-followup + . "${SWIFTLY_HOME_DIR:-$HOME/.swiftly}/env.sh" + hash -r + rm -f swiftly.pkg +else + # Official swiftly installer (https://www.swift.org/install/linux/) + curl -O "https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz" + tar zxf "swiftly-$(uname -m).tar.gz" + ./swiftly init --quiet-shell-followup + . "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh" + hash -r + rm -f "swiftly-$(uname -m).tar.gz" swiftly +fi diff --git a/@ether/library/Language/Swift/packages.sh b/@ether/library/Language/Swift/packages.sh new file mode 100755 index 00000000..3c201cfc --- /dev/null +++ b/@ether/library/Language/Swift/packages.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Swift" +REGISTRIES=( + "Swift Package Index: https://swiftpackageindex.com" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + echo "Visit: https://swiftpackageindex.com/search?query=$1" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + echo "Visit: https://swiftpackageindex.com/search?query=$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + echo "Add to Package.swift dependencies:" + echo " .package(url: \"https://github.com/OWNER/$1.git\", from: \"VERSION\")" + echo "" + echo "Find the URL at: https://swiftpackageindex.com/search?query=$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Swift/repl.sh b/@ether/library/Language/Swift/repl.sh new file mode 100755 index 00000000..937e364d --- /dev/null +++ b/@ether/library/Language/Swift/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec swift diff --git a/@ether/library/Language/Swift/run.sh b/@ether/library/Language/Swift/run.sh new file mode 100755 index 00000000..ff66fcc5 --- /dev/null +++ b/@ether/library/Language/Swift/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec swift "$@" diff --git a/@ether/library/Language/SymPy/check.sh b/@ether/library/Language/SymPy/check.sh new file mode 100755 index 00000000..e46180bc --- /dev/null +++ b/@ether/library/Language/SymPy/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import sympy" 2>/dev/null diff --git a/@ether/library/Language/SymPy/install.sh b/@ether/library/Language/SymPy/install.sh new file mode 100755 index 00000000..966cdce2 --- /dev/null +++ b/@ether/library/Language/SymPy/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# SymPy: symbolic mathematics for Python - https://www.sympy.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/sympy/sympy" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/sympy/sympy.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install sympy diff --git a/@ether/library/Language/SymPy/repl.sh b/@ether/library/Language/SymPy/repl.sh new file mode 100755 index 00000000..63cf2c4c --- /dev/null +++ b/@ether/library/Language/SymPy/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 -c "from sympy import *; import code; code.interact(local=dict(globals(), **locals()))" diff --git a/@ether/library/Language/SymPy/run.sh b/@ether/library/Language/SymPy/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/SymPy/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/SystemVerilog/check.sh b/@ether/library/Language/SystemVerilog/check.sh new file mode 100755 index 00000000..cf825976 --- /dev/null +++ b/@ether/library/Language/SystemVerilog/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v verilator >/dev/null 2>&1 diff --git a/@ether/library/Language/SystemVerilog/install.sh b/@ether/library/Language/SystemVerilog/install.sh new file mode 100755 index 00000000..9cb2a7ee --- /dev/null +++ b/@ether/library/Language/SystemVerilog/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# SystemVerilog: HDL - uses Verilator as simulator/linter +# https://www.veripool.org/verilator/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/chipsalliance/verible" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/chipsalliance/verible.git "$REPO_DIR" + fi + cd "$REPO_DIR" && bazel build //... + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install verilator +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y verilator +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y verilator +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm verilator +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/SystemVerilog/repl.sh b/@ether/library/Language/SystemVerilog/repl.sh new file mode 100755 index 00000000..a7bb84f1 --- /dev/null +++ b/@ether/library/Language/SystemVerilog/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "SystemVerilog does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/SystemVerilog/run.sh b/@ether/library/Language/SystemVerilog/run.sh new file mode 100755 index 00000000..5893247a --- /dev/null +++ b/@ether/library/Language/SystemVerilog/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec verilator --lint-only "$@" diff --git a/@ether/library/Language/TKET/check.sh b/@ether/library/Language/TKET/check.sh new file mode 100755 index 00000000..bc9727f6 --- /dev/null +++ b/@ether/library/Language/TKET/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import pytket" 2>/dev/null diff --git a/@ether/library/Language/TKET/install.sh b/@ether/library/Language/TKET/install.sh new file mode 100755 index 00000000..e71fec0e --- /dev/null +++ b/@ether/library/Language/TKET/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# TKET: Quantinuum quantum compiler - https://github.com/CQCL/tket +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/CQCL/tket" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/CQCL/tket.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install pytket diff --git a/@ether/library/Language/TKET/repl.sh b/@ether/library/Language/TKET/repl.sh new file mode 100755 index 00000000..c12cc206 --- /dev/null +++ b/@ether/library/Language/TKET/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 -c "from pytket import Circuit; import code; code.interact(local=dict(globals(), **locals()))" diff --git a/@ether/library/Language/TKET/run.sh b/@ether/library/Language/TKET/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/TKET/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/TLAPlus/check.sh b/@ether/library/Language/TLAPlus/check.sh new file mode 100755 index 00000000..cb883575 --- /dev/null +++ b/@ether/library/Language/TLAPlus/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v tlc >/dev/null 2>&1 || [[ -f "$HOME/.local/lib/tla/tla2tools.jar" ]] diff --git a/@ether/library/Language/TLAPlus/install.sh b/@ether/library/Language/TLAPlus/install.sh new file mode 100755 index 00000000..0ae52c34 --- /dev/null +++ b/@ether/library/Language/TLAPlus/install.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +# TLA+: formal specification language - https://lamport.azurewebsites.net/tla/tla.html +# Install TLA+ tools (TLC model checker, requires Java) +if [[ "$(uname)" == "Darwin" ]]; then + brew install tlaplus +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y default-jre + mkdir -p "$HOME/.local/lib/tla" + curl -fSL "https://github.com/tlaplus/tlaplus/releases/latest/download/tla2tools.jar" -o "$HOME/.local/lib/tla/tla2tools.jar" + mkdir -p "$HOME/.local/bin" + cat > "$HOME/.local/bin/tlc" << 'EOF' +#!/usr/bin/env bash +exec java -cp "$HOME/.local/lib/tla/tla2tools.jar" tlc2.TLC "$@" +EOF + chmod +x "$HOME/.local/bin/tlc" +elif command -v pacman >/dev/null 2>&1; then + echo "Install tlaplus from AUR: yay -S tlaplus" >&2 + exit 1 +else + echo "Download from https://github.com/tlaplus/tlaplus/releases" >&2; exit 1 +fi diff --git a/@ether/library/Language/TLAPlus/repl.sh b/@ether/library/Language/TLAPlus/repl.sh new file mode 100755 index 00000000..18e0c75a --- /dev/null +++ b/@ether/library/Language/TLAPlus/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "TLA+ does not have an interactive REPL (use the TLA+ Toolbox IDE)." >&2 +exit 1 diff --git a/@ether/library/Language/TLAPlus/run.sh b/@ether/library/Language/TLAPlus/run.sh new file mode 100755 index 00000000..953baf79 --- /dev/null +++ b/@ether/library/Language/TLAPlus/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v tlc >/dev/null 2>&1; then + exec tlc "$@" +else + exec java -cp "$HOME/.local/lib/tla/tla2tools.jar" tlc2.TLC "$@" +fi diff --git a/@ether/library/Language/TOML/check.sh b/@ether/library/Language/TOML/check.sh new file mode 100755 index 00000000..742e13d6 --- /dev/null +++ b/@ether/library/Language/TOML/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exit 0 diff --git a/@ether/library/Language/TOML/install.sh b/@ether/library/Language/TOML/install.sh new file mode 100755 index 00000000..ad1ebcb7 --- /dev/null +++ b/@ether/library/Language/TOML/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# TOML: data serialization format - https://toml.io/ +# No installation needed; TOML is a data format. +echo "TOML is a data format; no installation required." diff --git a/@ether/library/Language/TOML/repl.sh b/@ether/library/Language/TOML/repl.sh new file mode 100755 index 00000000..0f95497b --- /dev/null +++ b/@ether/library/Language/TOML/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "TOML is a data format; no REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/TOML/run.sh b/@ether/library/Language/TOML/run.sh new file mode 100755 index 00000000..a734e7cc --- /dev/null +++ b/@ether/library/Language/TOML/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$@" diff --git a/@ether/library/Language/TPS/check.sh b/@ether/library/Language/TPS/check.sh new file mode 100755 index 00000000..ee763df8 --- /dev/null +++ b/@ether/library/Language/TPS/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/theoremprover-museum/TPS" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/TPS/install.sh b/@ether/library/Language/TPS/install.sh new file mode 100755 index 00000000..0ebf5feb --- /dev/null +++ b/@ether/library/Language/TPS/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# TPS: Theorem Proving System - https://github.com/theoremprover-museum/TPS +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/theoremprover-museum/TPS" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/theoremprover-museum/TPS.git "$REPO_DIR" +fi +echo "TPS source cloned to $REPO_DIR" +echo "TPS requires Common Lisp (SBCL). See README in the repository for build instructions." diff --git a/@ether/library/Language/TPS/repl.sh b/@ether/library/Language/TPS/repl.sh new file mode 100755 index 00000000..3e870262 --- /dev/null +++ b/@ether/library/Language/TPS/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "TPS does not have a standalone REPL." >&2 +exit 1 diff --git a/@ether/library/Language/TPS/run.sh b/@ether/library/Language/TPS/run.sh new file mode 100755 index 00000000..bd4fa92c --- /dev/null +++ b/@ether/library/Language/TPS/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "TPS requires manual setup. See the repository README." >&2 +cat "$@" diff --git a/@ether/library/Language/TPTP/check.sh b/@ether/library/Language/TPTP/check.sh new file mode 100755 index 00000000..ba339315 --- /dev/null +++ b/@ether/library/Language/TPTP/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v eprover >/dev/null 2>&1 || exit 0 diff --git a/@ether/library/Language/TPTP/install.sh b/@ether/library/Language/TPTP/install.sh new file mode 100755 index 00000000..0383a3cb --- /dev/null +++ b/@ether/library/Language/TPTP/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# TPTP: problem format for automated theorem provers - https://www.tptp.org/ +# TPTP is a file format; install E theorem prover as a reference tool +if [[ "$(uname)" == "Darwin" ]]; then + brew install eprover +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y eprover +elif command -v pacman >/dev/null 2>&1; then + echo "Install eprover from AUR: yay -S eprover" >&2 +else + echo "Download E prover from https://wwwlehre.dhbw-stuttgart.de/~sschulz/E/E.html" >&2 +fi +echo "TPTP is a problem format. Install a theorem prover (E, Vampire, etc.) to process .p files." diff --git a/@ether/library/Language/TPTP/repl.sh b/@ether/library/Language/TPTP/repl.sh new file mode 100755 index 00000000..798208a3 --- /dev/null +++ b/@ether/library/Language/TPTP/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "TPTP is a problem format; no REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/TPTP/run.sh b/@ether/library/Language/TPTP/run.sh new file mode 100755 index 00000000..a8af82b8 --- /dev/null +++ b/@ether/library/Language/TPTP/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v eprover >/dev/null 2>&1; then + exec eprover --auto "$@" +else + cat "$@" +fi diff --git a/@ether/library/Language/TSV/check.sh b/@ether/library/Language/TSV/check.sh new file mode 100755 index 00000000..742e13d6 --- /dev/null +++ b/@ether/library/Language/TSV/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exit 0 diff --git a/@ether/library/Language/TSV/install.sh b/@ether/library/Language/TSV/install.sh new file mode 100755 index 00000000..f598725e --- /dev/null +++ b/@ether/library/Language/TSV/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# TSV: Tab-Separated Values data format +# No installation needed; TSV is a data format. +echo "TSV is a data format; no installation required." diff --git a/@ether/library/Language/TSV/repl.sh b/@ether/library/Language/TSV/repl.sh new file mode 100755 index 00000000..719c6ce6 --- /dev/null +++ b/@ether/library/Language/TSV/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "TSV is a data format; no REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/TSV/run.sh b/@ether/library/Language/TSV/run.sh new file mode 100755 index 00000000..a734e7cc --- /dev/null +++ b/@ether/library/Language/TSV/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$@" diff --git a/@ether/library/Language/Tact/check.sh b/@ether/library/Language/Tact/check.sh new file mode 100755 index 00000000..1302b93a --- /dev/null +++ b/@ether/library/Language/Tact/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v tact >/dev/null 2>&1 diff --git a/@ether/library/Language/Tact/install.sh b/@ether/library/Language/Tact/install.sh new file mode 100755 index 00000000..8e6efa17 --- /dev/null +++ b/@ether/library/Language/Tact/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Tact: TON blockchain smart contract language - https://tact-lang.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/tact-lang/tact" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/tact-lang/tact.git "$REPO_DIR" + fi + cd "$REPO_DIR" && npm install && npm run build + exit 0 +fi +npm install -g @tact-lang/compiler diff --git a/@ether/library/Language/Tact/packages.sh b/@ether/library/Language/Tact/packages.sh new file mode 100755 index 00000000..247f8055 --- /dev/null +++ b/@ether/library/Language/Tact/packages.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="Tact" +REGISTRIES=( + "npm (TON ecosystem): https://www.npmjs.com" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Note: Tact uses the npm ecosystem for package distribution." + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + if command -v npm &>/dev/null; then + npm search tact-"$@" + else + echo "Visit: https://www.npmjs.com/search?q=tact-$1" + fi + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + if command -v npm &>/dev/null; then + npm info "$1" + else + echo "Visit: https://www.npmjs.com/package/$1" + fi + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + npm install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/Tact/repl.sh b/@ether/library/Language/Tact/repl.sh new file mode 100755 index 00000000..bb5e9425 --- /dev/null +++ b/@ether/library/Language/Tact/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Tact does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Tact/run.sh b/@ether/library/Language/Tact/run.sh new file mode 100755 index 00000000..56ebbb79 --- /dev/null +++ b/@ether/library/Language/Tact/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec tact "$@" diff --git a/@ether/library/Language/Tcl/check.sh b/@ether/library/Language/Tcl/check.sh new file mode 100755 index 00000000..fba3cb34 --- /dev/null +++ b/@ether/library/Language/Tcl/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v tclsh >/dev/null 2>&1 diff --git a/@ether/library/Language/Tcl/install.sh b/@ether/library/Language/Tcl/install.sh new file mode 100755 index 00000000..2404b8bd --- /dev/null +++ b/@ether/library/Language/Tcl/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +# Tcl +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Tcl from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/tcl-src" + mkdir -p "$REPO_DIR" && cd "$REPO_DIR" + curl -LO https://prdownloads.sourceforge.net/tcl/tcl8.6.13-src.tar.gz + tar xzf tcl8.6.13-src.tar.gz + cd tcl8.6.13/unix + ./configure --prefix=/usr/local + make -j"$(nproc)" + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install tcl-tk +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y tcl +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y tcl +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm tcl +else + echo "Unsupported package manager. Use --from-source or visit https://www.tcl.tk/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Tcl/packages.sh b/@ether/library/Language/Tcl/packages.sh new file mode 100755 index 00000000..c9cf4975 --- /dev/null +++ b/@ether/library/Language/Tcl/packages.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/toc.md" + +usage() { + echo "Tcl Package Manager (tcllib + Teapot)" + echo "" + echo "Registry: $REGISTRY" + echo "" + echo "Usage: packages.sh [args]" + echo "" + echo "Commands:" + echo " search Search for packages" + echo " info Show package information" + echo " install Install a package" +} + +cmd_search() { + local query="$1" + echo "Search tcllib packages:" + echo " $REGISTRY" + echo "" + echo "Search ActiveState Teapot (if available):" + if command -v teacup &>/dev/null; then + teacup search "$query" + else + echo " teacup not found. Visit: https://core.tcl-lang.org/tcllib/" + fi +} + +cmd_info() { + local pkg="$1" + echo "Package: $pkg" + echo " tcllib docs: $REGISTRY" + if command -v teacup &>/dev/null; then + teacup describe "$pkg" + fi +} + +cmd_install() { + local pkg="$1" + if command -v teacup &>/dev/null; then + teacup install "$pkg" + else + echo "teacup not found. Install options:" + echo "" + echo " Debian/Ubuntu: sudo apt install tcllib" + echo " macOS (brew): brew install tcllib" + echo " ActiveTcl: https://www.activestate.com/products/tcl/" + echo "" + echo "For individual packages, teacup (from ActiveTcl) is recommended." + fi +} + +case "${1:-}" in + search) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh search "; exit 1; } + cmd_search "$1" + ;; + info) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh info "; exit 1; } + cmd_info "$1" + ;; + install) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh install "; exit 1; } + cmd_install "$1" + ;; + *) + usage + ;; +esac diff --git a/@ether/library/Language/Tcl/repl.sh b/@ether/library/Language/Tcl/repl.sh new file mode 100755 index 00000000..81bb3299 --- /dev/null +++ b/@ether/library/Language/Tcl/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec tclsh diff --git a/@ether/library/Language/Tcl/run.sh b/@ether/library/Language/Tcl/run.sh new file mode 100755 index 00000000..2a65b572 --- /dev/null +++ b/@ether/library/Language/Tcl/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec tclsh "$@" diff --git a/@ether/library/Language/Teal/check.sh b/@ether/library/Language/Teal/check.sh new file mode 100755 index 00000000..2a2f86da --- /dev/null +++ b/@ether/library/Language/Teal/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v goal >/dev/null 2>&1 diff --git a/@ether/library/Language/Teal/install.sh b/@ether/library/Language/Teal/install.sh new file mode 100755 index 00000000..7ed69a77 --- /dev/null +++ b/@ether/library/Language/Teal/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# TEAL: Algorand smart contract language - https://developer.algorand.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/algorand/go-algorand" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/algorand/go-algorand.git "$REPO_DIR" + fi + cd "$REPO_DIR" && make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew tap algorand/stable && brew install algorand +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y gnupg2 curl software-properties-common + curl -o - https://releases.algorand.com/key.pub | sudo tee /etc/apt/trusted.gpg.d/algorand.asc + sudo add-apt-repository "deb [arch=amd64] https://releases.algorand.com/deb/ stable main" + sudo apt-get update && sudo apt-get install -y algorand +else + echo "Download Algorand node from: https://developer.algorand.org/docs/run-a-node/setup/install/" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Teal/packages.sh b/@ether/library/Language/Teal/packages.sh new file mode 100755 index 00000000..d21f9fc3 --- /dev/null +++ b/@ether/library/Language/Teal/packages.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "TEAL does not have a package manager." +echo "Algorand PyTEAL library: pip install pyteal" diff --git a/@ether/library/Language/Teal/repl.sh b/@ether/library/Language/Teal/repl.sh new file mode 100755 index 00000000..7fce58cd --- /dev/null +++ b/@ether/library/Language/Teal/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "TEAL does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Teal/run.sh b/@ether/library/Language/Teal/run.sh new file mode 100755 index 00000000..8e37bed8 --- /dev/null +++ b/@ether/library/Language/Teal/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec goal clerk compile "$@" diff --git a/@ether/library/Language/TensorFlow/check.sh b/@ether/library/Language/TensorFlow/check.sh new file mode 100755 index 00000000..2d4dbb9f --- /dev/null +++ b/@ether/library/Language/TensorFlow/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import tensorflow" 2>/dev/null diff --git a/@ether/library/Language/TensorFlow/install.sh b/@ether/library/Language/TensorFlow/install.sh new file mode 100755 index 00000000..17fcd9d3 --- /dev/null +++ b/@ether/library/Language/TensorFlow/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# TensorFlow: ML framework - https://www.tensorflow.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/tensorflow/tensorflow" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/tensorflow/tensorflow.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./configure && bazel build //tensorflow/tools/pip_package:wheel + exit 0 +fi +pip install tensorflow diff --git a/@ether/library/Language/TensorFlow/repl.sh b/@ether/library/Language/TensorFlow/repl.sh new file mode 100755 index 00000000..fc922036 --- /dev/null +++ b/@ether/library/Language/TensorFlow/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 -c "import tensorflow as tf; print('TensorFlow', tf.__version__); import code; code.interact(local=dict(globals(), **locals()))" diff --git a/@ether/library/Language/TensorFlow/run.sh b/@ether/library/Language/TensorFlow/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/TensorFlow/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/TensorFlow_Probability/check.sh b/@ether/library/Language/TensorFlow_Probability/check.sh new file mode 100755 index 00000000..cf15234d --- /dev/null +++ b/@ether/library/Language/TensorFlow_Probability/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import tensorflow_probability" 2>/dev/null diff --git a/@ether/library/Language/TensorFlow_Probability/install.sh b/@ether/library/Language/TensorFlow_Probability/install.sh new file mode 100755 index 00000000..638a2153 --- /dev/null +++ b/@ether/library/Language/TensorFlow_Probability/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# TensorFlow Probability - https://github.com/tensorflow/probability +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/tensorflow/probability" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/tensorflow/probability.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install tensorflow-probability diff --git a/@ether/library/Language/TensorFlow_Probability/repl.sh b/@ether/library/Language/TensorFlow_Probability/repl.sh new file mode 100755 index 00000000..1142ba65 --- /dev/null +++ b/@ether/library/Language/TensorFlow_Probability/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 -c "import tensorflow_probability as tfp; import tensorflow as tf; print('TFP', tfp.__version__); import code; code.interact(local=dict(globals(), **locals()))" diff --git a/@ether/library/Language/TensorFlow_Probability/run.sh b/@ether/library/Language/TensorFlow_Probability/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/TensorFlow_Probability/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/Tera/check.sh b/@ether/library/Language/Tera/check.sh new file mode 100755 index 00000000..70365988 --- /dev/null +++ b/@ether/library/Language/Tera/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v tera >/dev/null 2>&1 diff --git a/@ether/library/Language/Tera/install.sh b/@ether/library/Language/Tera/install.sh new file mode 100755 index 00000000..d6e47d76 --- /dev/null +++ b/@ether/library/Language/Tera/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Tera: Rust template engine (Jinja2-like) - https://keats.github.io/tera/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Keats/tera" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Keats/tera.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + exit 0 +fi +cargo install tera-cli diff --git a/@ether/library/Language/Tera/repl.sh b/@ether/library/Language/Tera/repl.sh new file mode 100755 index 00000000..2bd111fd --- /dev/null +++ b/@ether/library/Language/Tera/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Tera does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Tera/run.sh b/@ether/library/Language/Tera/run.sh new file mode 100755 index 00000000..cbeece19 --- /dev/null +++ b/@ether/library/Language/Tera/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec tera --template "$@" diff --git a/@ether/library/Language/Terra/check.sh b/@ether/library/Language/Terra/check.sh new file mode 100755 index 00000000..17440536 --- /dev/null +++ b/@ether/library/Language/Terra/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v terra >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/terralang/terra" + [[ -x "$REPO_DIR/build/bin/terra" ]] +} diff --git a/@ether/library/Language/Terra/install.sh b/@ether/library/Language/Terra/install.sh new file mode 100755 index 00000000..d72043f2 --- /dev/null +++ b/@ether/library/Language/Terra/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Terra: low-level system programming language - https://terralang.org/ +# Requires LLVM and Clang +if [[ "$(uname)" == "Darwin" ]]; then + brew install llvm cmake +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y build-essential cmake llvm-dev clang libclang-dev +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gcc gcc-c++ cmake llvm-devel clang-devel +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm base-devel cmake llvm clang +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/terralang/terra" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/terralang/terra.git "$REPO_DIR" +fi +cd "$REPO_DIR" && cmake -B build && cmake --build build -j"$(nproc)" diff --git a/@ether/library/Language/Terra/repl.sh b/@ether/library/Language/Terra/repl.sh new file mode 100755 index 00000000..332ae15c --- /dev/null +++ b/@ether/library/Language/Terra/repl.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +if command -v terra >/dev/null 2>&1; then + exec terra +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/terralang/terra" + exec "$REPO_DIR/build/bin/terra" +fi diff --git a/@ether/library/Language/Terra/run.sh b/@ether/library/Language/Terra/run.sh new file mode 100755 index 00000000..49efb2e4 --- /dev/null +++ b/@ether/library/Language/Terra/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v terra >/dev/null 2>&1; then + exec terra "$@" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/terralang/terra" + exec "$REPO_DIR/build/bin/terra" "$@" +fi diff --git a/@ether/library/Language/Terraform/check.sh b/@ether/library/Language/Terraform/check.sh new file mode 100755 index 00000000..695ac941 --- /dev/null +++ b/@ether/library/Language/Terraform/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v terraform >/dev/null 2>&1 diff --git a/@ether/library/Language/Terraform/install.sh b/@ether/library/Language/Terraform/install.sh new file mode 100755 index 00000000..566df3ab --- /dev/null +++ b/@ether/library/Language/Terraform/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +# Terraform: infrastructure as code - https://www.terraform.io/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/hashicorp/terraform" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/hashicorp/terraform.git "$REPO_DIR" + fi + cd "$REPO_DIR" && go build -o "$HOME/.local/bin/terraform" . + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew tap hashicorp/tap && brew install hashicorp/tap/terraform +elif command -v apt-get >/dev/null 2>&1; then + wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg + echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list + sudo apt-get update && sudo apt-get install -y terraform +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y dnf-plugins-core + sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/fedora/hashicorp.repo + sudo dnf install -y terraform +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm terraform +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Terraform/repl.sh b/@ether/library/Language/Terraform/repl.sh new file mode 100755 index 00000000..59c8f9ee --- /dev/null +++ b/@ether/library/Language/Terraform/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec terraform console diff --git a/@ether/library/Language/Terraform/run.sh b/@ether/library/Language/Terraform/run.sh new file mode 100755 index 00000000..95718786 --- /dev/null +++ b/@ether/library/Language/Terraform/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec terraform "$@" diff --git a/@ether/library/Language/Thrift/check.sh b/@ether/library/Language/Thrift/check.sh new file mode 100755 index 00000000..45f1760b --- /dev/null +++ b/@ether/library/Language/Thrift/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v thrift >/dev/null 2>&1 diff --git a/@ether/library/Language/Thrift/install.sh b/@ether/library/Language/Thrift/install.sh new file mode 100755 index 00000000..443e1cf3 --- /dev/null +++ b/@ether/library/Language/Thrift/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +# Apache Thrift: RPC framework - https://thrift.apache.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/apache/thrift" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/apache/thrift.git "$REPO_DIR" + fi + cd "$REPO_DIR" && ./bootstrap.sh && ./configure && make -j"$(nproc)" && sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install thrift +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y thrift-compiler +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y thrift +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm thrift +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Thrift/repl.sh b/@ether/library/Language/Thrift/repl.sh new file mode 100755 index 00000000..6f6e52a5 --- /dev/null +++ b/@ether/library/Language/Thrift/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Thrift does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Thrift/run.sh b/@ether/library/Language/Thrift/run.sh new file mode 100755 index 00000000..2ad28164 --- /dev/null +++ b/@ether/library/Language/Thrift/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec thrift "$@" diff --git a/@ether/library/Language/Thue/check.sh b/@ether/library/Language/Thue/check.sh new file mode 100755 index 00000000..ee563a70 --- /dev/null +++ b/@ether/library/Language/Thue/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v thue >/dev/null 2>&1 diff --git a/@ether/library/Language/Thue/install.sh b/@ether/library/Language/Thue/install.sh new file mode 100755 index 00000000..8bfda18d --- /dev/null +++ b/@ether/library/Language/Thue/install.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail +# Thue: esoteric string rewriting language - https://esolangs.org/wiki/Thue +# Install a Python-based interpreter +pip install thue || { + echo "No standard package; using inline Python interpreter." >&2 + # Minimal Thue interpreter as fallback + mkdir -p "$HOME/.local/bin" + cat > "$HOME/.local/bin/thue" << 'INTERP' +#!/usr/bin/env python3 +import sys, random +def run(filename): + with open(filename) as f: + lines = f.read().split('\n') + rules = [] + data = '' + sep = False + for line in lines: + if line == '::=': + sep = True + continue + if not sep: + parts = line.split('::=', 1) + if len(parts) == 2: + rules.append((parts[0], parts[1])) + else: + data += line + '\n' + data = data.strip() + while True: + applicable = [(i, r) for i, r in enumerate(rules) if r[0] in data] + if not applicable: break + idx, (lhs, rhs) = random.choice(applicable) + if rhs.startswith('~'): + print(rhs[1:], end='') + rhs = '' + pos = data.find(lhs) + data = data[:pos] + rhs + data[pos+len(lhs):] +if __name__ == '__main__': + run(sys.argv[1]) +INTERP + chmod +x "$HOME/.local/bin/thue" +} diff --git a/@ether/library/Language/Thue/repl.sh b/@ether/library/Language/Thue/repl.sh new file mode 100755 index 00000000..3a495de4 --- /dev/null +++ b/@ether/library/Language/Thue/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Thue does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Thue/run.sh b/@ether/library/Language/Thue/run.sh new file mode 100755 index 00000000..c68c4e36 --- /dev/null +++ b/@ether/library/Language/Thue/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec thue "$@" diff --git a/@ether/library/Language/Treesitter/check.sh b/@ether/library/Language/Treesitter/check.sh new file mode 100755 index 00000000..cb89b0f0 --- /dev/null +++ b/@ether/library/Language/Treesitter/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v tree-sitter >/dev/null 2>&1 diff --git a/@ether/library/Language/Treesitter/install.sh b/@ether/library/Language/Treesitter/install.sh new file mode 100755 index 00000000..f2a74c7f --- /dev/null +++ b/@ether/library/Language/Treesitter/install.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +# Tree-sitter: incremental parsing library - https://tree-sitter.github.io/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/tree-sitter/tree-sitter" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/tree-sitter/tree-sitter.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + cp target/release/tree-sitter "$HOME/.local/bin/" 2>/dev/null || sudo cp target/release/tree-sitter /usr/local/bin/ + exit 0 +fi +if command -v cargo >/dev/null 2>&1; then + cargo install tree-sitter-cli +elif command -v npm >/dev/null 2>&1; then + npm install -g tree-sitter-cli +else + echo "Requires cargo or npm." >&2; exit 1 +fi diff --git a/@ether/library/Language/Treesitter/repl.sh b/@ether/library/Language/Treesitter/repl.sh new file mode 100755 index 00000000..0dbb06a7 --- /dev/null +++ b/@ether/library/Language/Treesitter/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec tree-sitter playground diff --git a/@ether/library/Language/Treesitter/run.sh b/@ether/library/Language/Treesitter/run.sh new file mode 100755 index 00000000..96f6d26c --- /dev/null +++ b/@ether/library/Language/Treesitter/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec tree-sitter parse "$@" diff --git a/@ether/library/Language/Troll/check.sh b/@ether/library/Language/Troll/check.sh new file mode 100755 index 00000000..2029174b --- /dev/null +++ b/@ether/library/Language/Troll/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v troll >/dev/null 2>&1 || { + TROLL_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/troll" + [[ -d "$TROLL_DIR" ]] +} diff --git a/@ether/library/Language/Troll/install.sh b/@ether/library/Language/Troll/install.sh new file mode 100755 index 00000000..8888f031 --- /dev/null +++ b/@ether/library/Language/Troll/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +# Troll: dice rolling language - https://hjemmesider.diku.dk/~torbenm/Troll/ +# Download pre-built binary or compile from source (requires SML) +if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y smlnj +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm smlnj +elif [[ "$(uname)" == "Darwin" ]]; then + brew install smlnj +fi +TROLL_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/troll" +mkdir -p "$TROLL_DIR" +curl -fSL "https://hjemmesider.diku.dk/~torbenm/Troll/Troll.zip" -o "$TROLL_DIR/Troll.zip" || { + echo "Download Troll manually from https://hjemmesider.diku.dk/~torbenm/Troll/" >&2 + exit 1 +} +cd "$TROLL_DIR" && unzip -o Troll.zip diff --git a/@ether/library/Language/Troll/repl.sh b/@ether/library/Language/Troll/repl.sh new file mode 100755 index 00000000..6cae8184 --- /dev/null +++ b/@ether/library/Language/Troll/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Troll does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Troll/run.sh b/@ether/library/Language/Troll/run.sh new file mode 100755 index 00000000..f3cfe245 --- /dev/null +++ b/@ether/library/Language/Troll/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v troll >/dev/null 2>&1; then + exec troll "$@" +else + TROLL_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/troll" + exec sml "$TROLL_DIR/troll.sml" "$@" +fi diff --git a/@ether/library/Language/TrumpScript/check.sh b/@ether/library/Language/TrumpScript/check.sh new file mode 100755 index 00000000..4cca0395 --- /dev/null +++ b/@ether/library/Language/TrumpScript/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v TrumpScript >/dev/null 2>&1 || python3 -c "import TrumpScript" 2>/dev/null diff --git a/@ether/library/Language/TrumpScript/install.sh b/@ether/library/Language/TrumpScript/install.sh new file mode 100755 index 00000000..b1227006 --- /dev/null +++ b/@ether/library/Language/TrumpScript/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# TrumpScript: esoteric language - https://github.com/samshadwell/TrumpScript +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/samshadwell/TrumpScript" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/samshadwell/TrumpScript.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install TrumpScript diff --git a/@ether/library/Language/TrumpScript/repl.sh b/@ether/library/Language/TrumpScript/repl.sh new file mode 100755 index 00000000..2946e977 --- /dev/null +++ b/@ether/library/Language/TrumpScript/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "TrumpScript does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/TrumpScript/run.sh b/@ether/library/Language/TrumpScript/run.sh new file mode 100755 index 00000000..cf57d602 --- /dev/null +++ b/@ether/library/Language/TrumpScript/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v TrumpScript >/dev/null 2>&1; then + exec TrumpScript "$@" +else + exec python3 -m TrumpScript "$@" +fi diff --git a/@ether/library/Language/Tuffy/check.sh b/@ether/library/Language/Tuffy/check.sh new file mode 100755 index 00000000..8162ab78 --- /dev/null +++ b/@ether/library/Language/Tuffy/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/HazyResearch/tuffy" +[[ -d "$REPO_DIR" ]] && command -v java >/dev/null 2>&1 diff --git a/@ether/library/Language/Tuffy/install.sh b/@ether/library/Language/Tuffy/install.sh new file mode 100755 index 00000000..a46d9fc6 --- /dev/null +++ b/@ether/library/Language/Tuffy/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# Tuffy: Markov Logic Network inference - https://github.com/HazyResearch/tuffy +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/HazyResearch/tuffy" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/HazyResearch/tuffy.git "$REPO_DIR" +fi +echo "Tuffy cloned to $REPO_DIR" +echo "Requires Java and PostgreSQL. See README for setup instructions." diff --git a/@ether/library/Language/Tuffy/repl.sh b/@ether/library/Language/Tuffy/repl.sh new file mode 100755 index 00000000..3f7df01d --- /dev/null +++ b/@ether/library/Language/Tuffy/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Tuffy does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Tuffy/run.sh b/@ether/library/Language/Tuffy/run.sh new file mode 100755 index 00000000..46536fb2 --- /dev/null +++ b/@ether/library/Language/Tuffy/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/HazyResearch/tuffy" +exec java -jar "$REPO_DIR/tuffy.jar" "$@" diff --git a/@ether/library/Language/Turing.jl/check.sh b/@ether/library/Language/Turing.jl/check.sh new file mode 100755 index 00000000..7d1f7997 --- /dev/null +++ b/@ether/library/Language/Turing.jl/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v julia >/dev/null 2>&1 && julia -e 'using Turing' 2>/dev/null diff --git a/@ether/library/Language/Turing.jl/install.sh b/@ether/library/Language/Turing.jl/install.sh new file mode 100755 index 00000000..be882426 --- /dev/null +++ b/@ether/library/Language/Turing.jl/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# Turing.jl: probabilistic programming in Julia - https://turinglang.org/ +# Requires Julia +if ! command -v julia >/dev/null 2>&1; then + echo "Julia is required. Install Julia first." >&2 + exit 1 +fi +julia -e 'using Pkg; Pkg.add("Turing")' diff --git a/@ether/library/Language/Turing.jl/repl.sh b/@ether/library/Language/Turing.jl/repl.sh new file mode 100755 index 00000000..fe4aaecd --- /dev/null +++ b/@ether/library/Language/Turing.jl/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec julia -e 'using Turing; import REPL; REPL.run_repl(REPL.LineEditREPL(REPL.Terminals.TTYTerminal("", stdin, stdout, stderr)))' diff --git a/@ether/library/Language/Turing.jl/run.sh b/@ether/library/Language/Turing.jl/run.sh new file mode 100755 index 00000000..6afc8fc0 --- /dev/null +++ b/@ether/library/Language/Turing.jl/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec julia "$@" diff --git a/@ether/library/Language/Twelf/check.sh b/@ether/library/Language/Twelf/check.sh new file mode 100755 index 00000000..9cc09e84 --- /dev/null +++ b/@ether/library/Language/Twelf/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +command -v twelf-server >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/standardml/twelf" + [[ -x "$REPO_DIR/bin/twelf-server" ]] +} diff --git a/@ether/library/Language/Twelf/install.sh b/@ether/library/Language/Twelf/install.sh new file mode 100755 index 00000000..cb06b491 --- /dev/null +++ b/@ether/library/Language/Twelf/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Twelf: logical framework - https://github.com/standardml/twelf +# Requires SML/NJ +if [[ "$(uname)" == "Darwin" ]]; then + brew install smlnj +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y smlnj ml-lex ml-yacc +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y smlnj +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm smlnj +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/standardml/twelf" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/standardml/twelf.git "$REPO_DIR" +fi +cd "$REPO_DIR" && make smlnj diff --git a/@ether/library/Language/Twelf/repl.sh b/@ether/library/Language/Twelf/repl.sh new file mode 100755 index 00000000..71034e5f --- /dev/null +++ b/@ether/library/Language/Twelf/repl.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +if command -v twelf-server >/dev/null 2>&1; then + exec twelf-server +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/standardml/twelf" + exec "$REPO_DIR/bin/twelf-server" +fi diff --git a/@ether/library/Language/Twelf/run.sh b/@ether/library/Language/Twelf/run.sh new file mode 100755 index 00000000..6816981a --- /dev/null +++ b/@ether/library/Language/Twelf/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v twelf-server >/dev/null 2>&1; then + exec twelf-server "$@" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/standardml/twelf" + exec "$REPO_DIR/bin/twelf-server" "$@" +fi diff --git a/@ether/library/Language/TypeScript/check.sh b/@ether/library/Language/TypeScript/check.sh new file mode 100755 index 00000000..55d89eef --- /dev/null +++ b/@ether/library/Language/TypeScript/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v tsc >/dev/null 2>&1 diff --git a/@ether/library/Language/TypeScript/install.sh b/@ether/library/Language/TypeScript/install.sh new file mode 100755 index 00000000..225497e9 --- /dev/null +++ b/@ether/library/Language/TypeScript/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v npm >/dev/null 2>&1; then + npm install -g typescript ts-node +elif command -v bun >/dev/null 2>&1; then + bun install -g typescript +else + echo "npm or bun required. Install Node.js first." >&2; exit 1 +fi diff --git a/@ether/library/Language/TypeScript/packages.sh b/@ether/library/Language/TypeScript/packages.sh new file mode 100755 index 00000000..23b57572 --- /dev/null +++ b/@ether/library/Language/TypeScript/packages.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +LANG_NAME="TypeScript" +REGISTRIES=( + "npm: https://www.npmjs.com" +) + +show_usage() { + echo "Package manager for $LANG_NAME" + echo "" + echo "Registries:" + for r in "${REGISTRIES[@]}"; do echo " $r"; done + echo "" + echo "Usage: $0 {search|info|install} " +} + +cmd="${1:-}" +shift || true + +case "$cmd" in + search) + [[ $# -eq 0 ]] && { echo "Usage: $0 search "; exit 1; } + npm search "$@" + ;; + info) + [[ $# -eq 0 ]] && { echo "Usage: $0 info "; exit 1; } + npm info "$1" + ;; + install) + [[ $# -eq 0 ]] && { echo "Usage: $0 install "; exit 1; } + npm install "$1" + ;; + *) + show_usage + ;; +esac diff --git a/@ether/library/Language/TypeScript/repl.sh b/@ether/library/Language/TypeScript/repl.sh new file mode 100755 index 00000000..049d527a --- /dev/null +++ b/@ether/library/Language/TypeScript/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +if command -v bun >/dev/null 2>&1; then + exec bun repl +elif command -v ts-node >/dev/null 2>&1; then + exec ts-node +else + exec npx ts-node +fi diff --git a/@ether/library/Language/TypeScript/run.sh b/@ether/library/Language/TypeScript/run.sh new file mode 100755 index 00000000..1d7369b6 --- /dev/null +++ b/@ether/library/Language/TypeScript/run.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +if command -v bun >/dev/null 2>&1; then + exec bun run "$file" +elif command -v ts-node >/dev/null 2>&1; then + exec ts-node "$file" +elif command -v npx >/dev/null 2>&1; then + exec npx ts-node "$file" +else + tsc "$file" --outDir /tmp && node "/tmp/$(basename "${file%.ts}.js")" +fi diff --git a/@ether/library/Language/Typst/check.sh b/@ether/library/Language/Typst/check.sh new file mode 100755 index 00000000..4e8009a1 --- /dev/null +++ b/@ether/library/Language/Typst/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v typst >/dev/null 2>&1 diff --git a/@ether/library/Language/Typst/install.sh b/@ether/library/Language/Typst/install.sh new file mode 100755 index 00000000..2915df2b --- /dev/null +++ b/@ether/library/Language/Typst/install.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# Typst - modern typesetting system +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Typst from source via cargo..." + cargo install --git https://github.com/typst/typst --locked typst-cli + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install typst +elif command -v cargo >/dev/null 2>&1; then + cargo install typst-cli +elif command -v apt-get >/dev/null 2>&1; then + echo "Typst is not in standard repos. Install via cargo: cargo install typst-cli" >&2 + echo "Or download from https://github.com/typst/typst/releases" >&2; exit 1 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm typst +else + echo "Install via cargo: cargo install typst-cli" >&2 + echo "Or download from https://github.com/typst/typst/releases" >&2; exit 1 +fi diff --git a/@ether/library/Language/Typst/packages.sh b/@ether/library/Language/Typst/packages.sh new file mode 100755 index 00000000..f17ab79c --- /dev/null +++ b/@ether/library/Language/Typst/packages.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="https://packages.typst.app" + +usage() { + echo "Typst Package Manager (Typst Universe)" + echo "" + echo "Registry: $REGISTRY" + echo "" + echo "Usage: packages.sh [args]" + echo "" + echo "Commands:" + echo " search Search for packages" + echo " info Show package information" + echo " install Install a package (add import to .typ file)" +} + +cmd_search() { + local query="$1" + echo "Search Typst Universe:" + echo " $REGISTRY/?q=$query" +} + +cmd_info() { + local pkg="$1" + echo "Package info:" + echo " $REGISTRY/preview/$pkg" +} + +cmd_install() { + local pkg="$1" + echo "Add to your .typ file:" + echo " #import \"@preview/$pkg:VERSION\"" + echo "" + echo "Replace VERSION with the desired version (e.g., 0.1.0)." + echo "Typst downloads packages automatically on compilation." + echo "" + echo "Find available versions at: $REGISTRY/preview/$pkg" +} + +case "${1:-}" in + search) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh search "; exit 1; } + cmd_search "$1" + ;; + info) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh info "; exit 1; } + cmd_info "$1" + ;; + install) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh install "; exit 1; } + cmd_install "$1" + ;; + *) + usage + ;; +esac diff --git a/@ether/library/Language/Typst/repl.sh b/@ether/library/Language/Typst/repl.sh new file mode 100755 index 00000000..cb8b3d9c --- /dev/null +++ b/@ether/library/Language/Typst/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Typst does not have an interactive REPL. Use: typst watch " diff --git a/@ether/library/Language/Typst/run.sh b/@ether/library/Language/Typst/run.sh new file mode 100755 index 00000000..a3ee0f81 --- /dev/null +++ b/@ether/library/Language/Typst/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec typst compile "$@" diff --git a/@ether/library/Language/Uiua/check.sh b/@ether/library/Language/Uiua/check.sh new file mode 100755 index 00000000..022eeb16 --- /dev/null +++ b/@ether/library/Language/Uiua/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v uiua >/dev/null 2>&1 diff --git a/@ether/library/Language/Uiua/install.sh b/@ether/library/Language/Uiua/install.sh new file mode 100755 index 00000000..d44c6bb8 --- /dev/null +++ b/@ether/library/Language/Uiua/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Uiua: stack-based array language - https://www.uiua.org/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/uiua-lang/uiua" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/uiua-lang/uiua.git "$REPO_DIR" + fi + cd "$REPO_DIR" && cargo build --release + cp target/release/uiua "$HOME/.local/bin/" 2>/dev/null || sudo cp target/release/uiua /usr/local/bin/ + exit 0 +fi +cargo install uiua diff --git a/@ether/library/Language/Uiua/repl.sh b/@ether/library/Language/Uiua/repl.sh new file mode 100755 index 00000000..26b12cb0 --- /dev/null +++ b/@ether/library/Language/Uiua/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec uiua repl diff --git a/@ether/library/Language/Uiua/run.sh b/@ether/library/Language/Uiua/run.sh new file mode 100755 index 00000000..9fa1c4ba --- /dev/null +++ b/@ether/library/Language/Uiua/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec uiua run "$@" diff --git a/@ether/library/Language/Unicode/check.sh b/@ether/library/Language/Unicode/check.sh new file mode 100755 index 00000000..742e13d6 --- /dev/null +++ b/@ether/library/Language/Unicode/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exit 0 diff --git a/@ether/library/Language/Unicode/install.sh b/@ether/library/Language/Unicode/install.sh new file mode 100755 index 00000000..1ab4ef72 --- /dev/null +++ b/@ether/library/Language/Unicode/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# Unicode: character encoding standard +# No installation needed; Unicode is a data/encoding standard. +echo "Unicode is an encoding standard; no installation required." diff --git a/@ether/library/Language/Unicode/repl.sh b/@ether/library/Language/Unicode/repl.sh new file mode 100755 index 00000000..497a026f --- /dev/null +++ b/@ether/library/Language/Unicode/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Unicode is an encoding standard; no REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/Unicode/run.sh b/@ether/library/Language/Unicode/run.sh new file mode 100755 index 00000000..a734e7cc --- /dev/null +++ b/@ether/library/Language/Unicode/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$@" diff --git a/@ether/library/Language/Unison/check.sh b/@ether/library/Language/Unison/check.sh new file mode 100755 index 00000000..8e65d7cc --- /dev/null +++ b/@ether/library/Language/Unison/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v ucm >/dev/null 2>&1 diff --git a/@ether/library/Language/Unison/install.sh b/@ether/library/Language/Unison/install.sh new file mode 100755 index 00000000..0e1be1a1 --- /dev/null +++ b/@ether/library/Language/Unison/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Unison from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/unisonweb/unison" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/unisonweb/unison.git "$REPO_DIR" + fi + cd "$REPO_DIR" + command -v stack >/dev/null 2>&1 || { echo "Haskell Stack required. Install via: curl -sSL https://get.haskellstack.org/ | sh" >&2; exit 1; } + stack build + stack install + exit 0 +fi +# Official install: https://www.unison-lang.org/docs/installation/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install unisonweb/unison/ucm +elif command -v apt-get >/dev/null 2>&1 || command -v dnf >/dev/null 2>&1 || command -v pacman >/dev/null 2>&1; then + # Official Linux installer + curl -fsSL https://github.com/unisonweb/unison/releases/latest/download/ucm-linux.tar.gz -o /tmp/ucm-linux.tar.gz + mkdir -p "$HOME/.local/bin" + tar -xzf /tmp/ucm-linux.tar.gz -C "$HOME/.local/bin" + rm -f /tmp/ucm-linux.tar.gz +else + echo "Unsupported platform. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/Unison/repl.sh b/@ether/library/Language/Unison/repl.sh new file mode 100755 index 00000000..7496fcb6 --- /dev/null +++ b/@ether/library/Language/Unison/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ucm diff --git a/@ether/library/Language/Unison/run.sh b/@ether/library/Language/Unison/run.sh new file mode 100755 index 00000000..ad30f04a --- /dev/null +++ b/@ether/library/Language/Unison/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec ucm run "$1" diff --git a/@ether/library/Language/UnrealScript/check.sh b/@ether/library/Language/UnrealScript/check.sh new file mode 100755 index 00000000..99b5b05e --- /dev/null +++ b/@ether/library/Language/UnrealScript/check.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +# UnrealScript is part of UDK/UE3; no standalone command to check +echo "UnrealScript requires the Unreal Development Kit." >&2 +exit 1 diff --git a/@ether/library/Language/UnrealScript/install.sh b/@ether/library/Language/UnrealScript/install.sh new file mode 100755 index 00000000..25a7c1eb --- /dev/null +++ b/@ether/library/Language/UnrealScript/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# UnrealScript is compiled within the Unreal Engine editor (UDK/UE3). +# There is no standalone compiler. Install the Unreal Development Kit. +echo "UnrealScript requires the Unreal Development Kit (UDK) or Unreal Engine 3." +echo "Download from: https://www.unrealengine.com/" +echo "No standalone installer available." >&2 +exit 1 diff --git a/@ether/library/Language/UnrealScript/repl.sh b/@ether/library/Language/UnrealScript/repl.sh new file mode 100755 index 00000000..92e671f8 --- /dev/null +++ b/@ether/library/Language/UnrealScript/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "UnrealScript does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/UnrealScript/run.sh b/@ether/library/Language/UnrealScript/run.sh new file mode 100755 index 00000000..fff717e5 --- /dev/null +++ b/@ether/library/Language/UnrealScript/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "UnrealScript must be compiled within the Unreal Development Kit." >&2 +exit 1 diff --git a/@ether/library/Language/V/check.sh b/@ether/library/Language/V/check.sh new file mode 100755 index 00000000..a1aff750 --- /dev/null +++ b/@ether/library/Language/V/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v v >/dev/null 2>&1 diff --git a/@ether/library/Language/V/install.sh b/@ether/library/Language/V/install.sh new file mode 100755 index 00000000..b7c04465 --- /dev/null +++ b/@ether/library/Language/V/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +# V language - https://vlang.io/ +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/vlang/v" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/vlang/v.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make +sudo ./v symlink || { mkdir -p "$HOME/.local/bin" && ln -sf "$REPO_DIR/v" "$HOME/.local/bin/v"; } diff --git a/@ether/library/Language/V/repl.sh b/@ether/library/Language/V/repl.sh new file mode 100755 index 00000000..13c4ffce --- /dev/null +++ b/@ether/library/Language/V/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec v repl diff --git a/@ether/library/Language/V/run.sh b/@ether/library/Language/V/run.sh new file mode 100755 index 00000000..20005188 --- /dev/null +++ b/@ether/library/Language/V/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec v run "$1" diff --git a/@ether/library/Language/VDM/check.sh b/@ether/library/Language/VDM/check.sh new file mode 100755 index 00000000..ead81d81 --- /dev/null +++ b/@ether/library/Language/VDM/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v overture >/dev/null 2>&1 || [[ -f "$HOME/.local/lib/overture/overture.jar" ]] diff --git a/@ether/library/Language/VDM/install.sh b/@ether/library/Language/VDM/install.sh new file mode 100755 index 00000000..75d7460a --- /dev/null +++ b/@ether/library/Language/VDM/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +# Vienna Development Method - Overture Tool: https://www.overturetool.org/ +# Overture is a Java-based IDE/tool for VDM +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask overture || true +fi +# Download Overture release for all platforms +RELEASE_URL="https://github.com/overturetool/overture/releases/latest" +DOWNLOAD_URL=$(curl -sSL "$RELEASE_URL" | grep -oP 'href="[^"]*\.jar"' | head -1 | cut -d'"' -f2) +if [[ -n "${DOWNLOAD_URL:-}" ]]; then + mkdir -p "$HOME/.local/lib/overture" + curl -fsSL "https://github.com${DOWNLOAD_URL}" -o "$HOME/.local/lib/overture/overture.jar" +else + echo "Download Overture manually from: https://www.overturetool.org/" >&2 + exit 1 +fi diff --git a/@ether/library/Language/VDM/repl.sh b/@ether/library/Language/VDM/repl.sh new file mode 100755 index 00000000..3741575d --- /dev/null +++ b/@ether/library/Language/VDM/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "VDM (Overture) does not provide a command-line REPL." >&2 +exit 1 diff --git a/@ether/library/Language/VDM/run.sh b/@ether/library/Language/VDM/run.sh new file mode 100755 index 00000000..add29767 --- /dev/null +++ b/@ether/library/Language/VDM/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v overture >/dev/null 2>&1; then + exec overture "$1" +else + exec java -jar "$HOME/.local/lib/overture/overture.jar" "$1" +fi diff --git a/@ether/library/Language/VHDL/check.sh b/@ether/library/Language/VHDL/check.sh new file mode 100755 index 00000000..91bb6a35 --- /dev/null +++ b/@ether/library/Language/VHDL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v ghdl >/dev/null 2>&1 diff --git a/@ether/library/Language/VHDL/install.sh b/@ether/library/Language/VHDL/install.sh new file mode 100755 index 00000000..fe461033 --- /dev/null +++ b/@ether/library/Language/VHDL/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# VHDL - GHDL is the open-source VHDL simulator +# https://github.com/ghdl/ghdl +if [[ "$(uname)" == "Darwin" ]]; then + brew install ghdl +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y ghdl +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y ghdl +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm ghdl-gcc || sudo pacman -S --noconfirm ghdl +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/VHDL/repl.sh b/@ether/library/Language/VHDL/repl.sh new file mode 100755 index 00000000..43b93949 --- /dev/null +++ b/@ether/library/Language/VHDL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "VHDL does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/VHDL/run.sh b/@ether/library/Language/VHDL/run.sh new file mode 100755 index 00000000..808316ef --- /dev/null +++ b/@ether/library/Language/VHDL/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +FILE="$1" +BASENAME="$(basename "$FILE" .vhd)" +ghdl -a "$FILE" && ghdl -e "$BASENAME" && ghdl -r "$BASENAME" diff --git a/@ether/library/Language/Vala/check.sh b/@ether/library/Language/Vala/check.sh new file mode 100755 index 00000000..aa8ae56c --- /dev/null +++ b/@ether/library/Language/Vala/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v valac >/dev/null 2>&1 diff --git a/@ether/library/Language/Vala/install.sh b/@ether/library/Language/Vala/install.sh new file mode 100755 index 00000000..304648bf --- /dev/null +++ b/@ether/library/Language/Vala/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Vala +if [[ "$(uname)" == "Darwin" ]]; then + brew install vala +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y valac +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y vala +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm vala +else + echo "Unsupported package manager. Visit https://vala.dev/" >&2; exit 1 +fi diff --git a/@ether/library/Language/Vala/packages.sh b/@ether/library/Language/Vala/packages.sh new file mode 100755 index 00000000..3c4141f2 --- /dev/null +++ b/@ether/library/Language/Vala/packages.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +case "${1:-}" in + search) + shift + [[ $# -lt 1 ]] && { echo "Usage: packages.sh search "; exit 1; } + echo "Vala uses system libraries via pkg-config." + echo "Search Valadoc:" + echo " https://valadoc.org/search?q=$1" + ;; + *) + echo "Vala uses system libraries via pkg-config." + echo "Browse GNOME libraries: https://valadoc.org" + ;; +esac diff --git a/@ether/library/Language/Vala/repl.sh b/@ether/library/Language/Vala/repl.sh new file mode 100755 index 00000000..88820650 --- /dev/null +++ b/@ether/library/Language/Vala/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Vala does not have an interactive REPL." diff --git a/@ether/library/Language/Vala/run.sh b/@ether/library/Language/Vala/run.sh new file mode 100755 index 00000000..6aea8b71 --- /dev/null +++ b/@ether/library/Language/Vala/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +FILE="$1" +shift +valac "$FILE" -o /tmp/vala_out && /tmp/vala_out "$@" diff --git a/@ether/library/Language/Vale/check.sh b/@ether/library/Language/Vale/check.sh new file mode 100755 index 00000000..7281cb22 --- /dev/null +++ b/@ether/library/Language/Vale/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v vale >/dev/null 2>&1 || command -v valec >/dev/null 2>&1 diff --git a/@ether/library/Language/Vale/install.sh b/@ether/library/Language/Vale/install.sh new file mode 100755 index 00000000..14562113 --- /dev/null +++ b/@ether/library/Language/Vale/install.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Vale from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ValeLang/Vale" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ValeLang/Vale.git "$REPO_DIR" + fi + cd "$REPO_DIR" + cmake -B build && cmake --build build + exit 0 +fi +# Official: download release from https://vale.dev/ +OS="$(uname -s)" +ARCH="$(uname -m)" +if [[ "$OS" == "Darwin" ]]; then + PLATFORM="mac" +elif [[ "$OS" == "Linux" ]]; then + PLATFORM="linux" +else + echo "Unsupported platform. Use --from-source." >&2; exit 1 +fi +RELEASE_URL=$(curl -sSL https://api.github.com/repos/ValeLang/Vale/releases/latest | grep "browser_download_url.*${PLATFORM}" | head -1 | cut -d'"' -f4) +if [[ -z "$RELEASE_URL" ]]; then + echo "Could not find release for platform $PLATFORM. Use --from-source." >&2; exit 1 +fi +mkdir -p "$HOME/.local/bin" +curl -fsSL "$RELEASE_URL" -o /tmp/vale-release.zip +unzip -o /tmp/vale-release.zip -d "$HOME/.local/bin/vale" +rm -f /tmp/vale-release.zip diff --git a/@ether/library/Language/Vale/repl.sh b/@ether/library/Language/Vale/repl.sh new file mode 100755 index 00000000..4bceff9b --- /dev/null +++ b/@ether/library/Language/Vale/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Vale does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Vale/run.sh b/@ether/library/Language/Vale/run.sh new file mode 100755 index 00000000..ccaf4f5b --- /dev/null +++ b/@ether/library/Language/Vale/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v valec >/dev/null 2>&1; then + valec build "$1" -o /tmp/vale_out && /tmp/vale_out +else + vale run "$1" +fi diff --git a/@ether/library/Language/Vampire/check.sh b/@ether/library/Language/Vampire/check.sh new file mode 100755 index 00000000..1330bf90 --- /dev/null +++ b/@ether/library/Language/Vampire/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v vampire >/dev/null 2>&1 diff --git a/@ether/library/Language/Vampire/install.sh b/@ether/library/Language/Vampire/install.sh new file mode 100755 index 00000000..008908d0 --- /dev/null +++ b/@ether/library/Language/Vampire/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Vampire theorem prover - https://vprover.github.io/ +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/vprover/vampire" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/vprover/vampire.git "$REPO_DIR" +fi +cd "$REPO_DIR" +mkdir -p build && cd build +cmake .. && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" +mkdir -p "$HOME/.local/bin" +cp bin/vampire "$HOME/.local/bin/" || true diff --git a/@ether/library/Language/Vampire/repl.sh b/@ether/library/Language/Vampire/repl.sh new file mode 100755 index 00000000..43a4dad7 --- /dev/null +++ b/@ether/library/Language/Vampire/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Vampire does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Vampire/run.sh b/@ether/library/Language/Vampire/run.sh new file mode 100755 index 00000000..8d430392 --- /dev/null +++ b/@ether/library/Language/Vampire/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec vampire "$1" diff --git a/@ether/library/Language/VauCalculus/check.sh b/@ether/library/Language/VauCalculus/check.sh new file mode 100755 index 00000000..5f2e7123 --- /dev/null +++ b/@ether/library/Language/VauCalculus/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v vau >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/breckinloggins/vau" + [[ -x "$REPO_DIR/vau" ]] +} diff --git a/@ether/library/Language/VauCalculus/install.sh b/@ether/library/Language/VauCalculus/install.sh new file mode 100755 index 00000000..a007911e --- /dev/null +++ b/@ether/library/Language/VauCalculus/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Vau Calculus - https://github.com/breckinloggins/vau +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/breckinloggins/vau" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/breckinloggins/vau.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make || gcc -o vau vau.c +mkdir -p "$HOME/.local/bin" +cp vau "$HOME/.local/bin/" || true diff --git a/@ether/library/Language/VauCalculus/repl.sh b/@ether/library/Language/VauCalculus/repl.sh new file mode 100755 index 00000000..b921c024 --- /dev/null +++ b/@ether/library/Language/VauCalculus/repl.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v vau >/dev/null 2>&1; then + exec vau +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/breckinloggins/vau" + exec "$REPO_DIR/vau" +fi diff --git a/@ether/library/Language/VauCalculus/run.sh b/@ether/library/Language/VauCalculus/run.sh new file mode 100755 index 00000000..1943a109 --- /dev/null +++ b/@ether/library/Language/VauCalculus/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v vau >/dev/null 2>&1; then + exec vau "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/breckinloggins/vau" + exec "$REPO_DIR/vau" "$1" +fi diff --git a/@ether/library/Language/Velato/check.sh b/@ether/library/Language/Velato/check.sh new file mode 100755 index 00000000..1f8e4082 --- /dev/null +++ b/@ether/library/Language/Velato/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Velato has no standalone interpreter to check." >&2 +exit 1 diff --git a/@ether/library/Language/Velato/install.sh b/@ether/library/Language/Velato/install.sh new file mode 100755 index 00000000..7a090a18 --- /dev/null +++ b/@ether/library/Language/Velato/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# Velato - esoteric language using MIDI files +# No official package; typically run via .NET/Mono interpreter +echo "Velato is an esoteric language that uses MIDI files as source code." +echo "See: https://velato.net/ and https://esolangs.org/wiki/Velato" +echo "No standard package manager install available." >&2 +exit 1 diff --git a/@ether/library/Language/Velato/repl.sh b/@ether/library/Language/Velato/repl.sh new file mode 100755 index 00000000..a95e696f --- /dev/null +++ b/@ether/library/Language/Velato/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Velato does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Velato/run.sh b/@ether/library/Language/Velato/run.sh new file mode 100755 index 00000000..710b1815 --- /dev/null +++ b/@ether/library/Language/Velato/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Velato requires a specialized interpreter for MIDI-based source." >&2 +exit 1 diff --git a/@ether/library/Language/Velocity/check.sh b/@ether/library/Language/Velocity/check.sh new file mode 100755 index 00000000..a2621083 --- /dev/null +++ b/@ether/library/Language/Velocity/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v java >/dev/null 2>&1 && ls "$HOME/.local/lib/velocity"/velocity-engine-core-*.jar >/dev/null 2>&1 diff --git a/@ether/library/Language/Velocity/install.sh b/@ether/library/Language/Velocity/install.sh new file mode 100755 index 00000000..f3821492 --- /dev/null +++ b/@ether/library/Language/Velocity/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Apache Velocity - Java-based template engine +# https://velocity.apache.org/ +# Requires Java and is used as a library, not a standalone tool +command -v java >/dev/null 2>&1 || { + echo "Java is required for Apache Velocity." >&2 + exit 1 +} +VELOCITY_VERSION="2.3" +mkdir -p "$HOME/.local/lib/velocity" +curl -fsSL "https://dlcdn.apache.org/velocity/engine/${VELOCITY_VERSION}/velocity-engine-core-${VELOCITY_VERSION}.jar" \ + -o "$HOME/.local/lib/velocity/velocity-engine-core-${VELOCITY_VERSION}.jar" || { + echo "Download Velocity from: https://velocity.apache.org/download.cgi" >&2 + exit 1 +} diff --git a/@ether/library/Language/Velocity/repl.sh b/@ether/library/Language/Velocity/repl.sh new file mode 100755 index 00000000..aafbc718 --- /dev/null +++ b/@ether/library/Language/Velocity/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Apache Velocity does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Velocity/run.sh b/@ether/library/Language/Velocity/run.sh new file mode 100755 index 00000000..71dc56e4 --- /dev/null +++ b/@ether/library/Language/Velocity/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Apache Velocity is a Java template library, not a standalone runner." >&2 +echo "Use it within a Java project." >&2 +cat "$1" diff --git a/@ether/library/Language/Venture/check.sh b/@ether/library/Language/Venture/check.sh new file mode 100755 index 00000000..95be6458 --- /dev/null +++ b/@ether/library/Language/Venture/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import venture" 2>/dev/null || command -v venture >/dev/null 2>&1 diff --git a/@ether/library/Language/Venture/install.sh b/@ether/library/Language/Venture/install.sh new file mode 100755 index 00000000..5b32296c --- /dev/null +++ b/@ether/library/Language/Venture/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# Venture - probabilistic programming - https://github.com/probcomp/Venturecxx +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/probcomp/Venturecxx" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/probcomp/Venturecxx.git "$REPO_DIR" +fi +cd "$REPO_DIR" +pip install -e . || pip install . diff --git a/@ether/library/Language/Venture/repl.sh b/@ether/library/Language/Venture/repl.sh new file mode 100755 index 00000000..ec606e2e --- /dev/null +++ b/@ether/library/Language/Venture/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec venture diff --git a/@ether/library/Language/Venture/run.sh b/@ether/library/Language/Venture/run.sh new file mode 100755 index 00000000..c2d499ef --- /dev/null +++ b/@ether/library/Language/Venture/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec venture "$1" diff --git a/@ether/library/Language/Verilog/check.sh b/@ether/library/Language/Verilog/check.sh new file mode 100755 index 00000000..1e86a202 --- /dev/null +++ b/@ether/library/Language/Verilog/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v iverilog >/dev/null 2>&1 diff --git a/@ether/library/Language/Verilog/install.sh b/@ether/library/Language/Verilog/install.sh new file mode 100755 index 00000000..511b946a --- /dev/null +++ b/@ether/library/Language/Verilog/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Verilog - hardware description language +# Icarus Verilog is the standard open-source simulator +if [[ "$(uname)" == "Darwin" ]]; then + brew install icarus-verilog +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y iverilog +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y iverilog +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm iverilog +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Verilog/repl.sh b/@ether/library/Language/Verilog/repl.sh new file mode 100755 index 00000000..be5ec4ec --- /dev/null +++ b/@ether/library/Language/Verilog/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Verilog does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Verilog/run.sh b/@ether/library/Language/Verilog/run.sh new file mode 100755 index 00000000..fcc76c0c --- /dev/null +++ b/@ether/library/Language/Verilog/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +iverilog -o /tmp/verilog_out "$1" && vvp /tmp/verilog_out diff --git a/@ether/library/Language/Verse/check.sh b/@ether/library/Language/Verse/check.sh new file mode 100755 index 00000000..f8509108 --- /dev/null +++ b/@ether/library/Language/Verse/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Verse requires the Unreal Editor for Fortnite (UEFN)." >&2 +exit 1 diff --git a/@ether/library/Language/Verse/install.sh b/@ether/library/Language/Verse/install.sh new file mode 100755 index 00000000..6ded01e2 --- /dev/null +++ b/@ether/library/Language/Verse/install.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# Verse is embedded in Unreal Engine / Fortnite Creative (UEFN). +# There is no standalone compiler. It requires Epic Games' UEFN. +echo "Verse is part of Unreal Editor for Fortnite (UEFN)." +echo "Download from: https://dev.epicgames.com/documentation/en-us/fortnite/verse-language-reference" +echo "No standalone installer available." >&2 +exit 1 diff --git a/@ether/library/Language/Verse/repl.sh b/@ether/library/Language/Verse/repl.sh new file mode 100755 index 00000000..687bca90 --- /dev/null +++ b/@ether/library/Language/Verse/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Verse does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Verse/run.sh b/@ether/library/Language/Verse/run.sh new file mode 100755 index 00000000..daa71393 --- /dev/null +++ b/@ether/library/Language/Verse/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Verse must be run within Unreal Editor for Fortnite." >&2 +exit 1 diff --git a/@ether/library/Language/VimScript/check.sh b/@ether/library/Language/VimScript/check.sh new file mode 100755 index 00000000..41c3f978 --- /dev/null +++ b/@ether/library/Language/VimScript/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v vim >/dev/null 2>&1 diff --git a/@ether/library/Language/VimScript/install.sh b/@ether/library/Language/VimScript/install.sh new file mode 100755 index 00000000..b1925723 --- /dev/null +++ b/@ether/library/Language/VimScript/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Vim from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/vim/vim" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/vim/vim.git "$REPO_DIR" + fi + cd "$REPO_DIR" + ./configure --prefix="$HOME/.local" && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" && make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install vim +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y vim +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y vim +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm vim +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/VimScript/repl.sh b/@ether/library/Language/VimScript/repl.sh new file mode 100755 index 00000000..1ff56676 --- /dev/null +++ b/@ether/library/Language/VimScript/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "VimScript does not have a standalone REPL. Use :commands inside Vim." >&2 +exit 1 diff --git a/@ether/library/Language/VimScript/run.sh b/@ether/library/Language/VimScript/run.sh new file mode 100755 index 00000000..70b0fd71 --- /dev/null +++ b/@ether/library/Language/VimScript/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec vim -e -s -S "$1" +qa diff --git a/@ether/library/Language/Virgil/check.sh b/@ether/library/Language/Virgil/check.sh new file mode 100755 index 00000000..92c09603 --- /dev/null +++ b/@ether/library/Language/Virgil/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v v3c >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/titzer/virgil" + [[ -x "$REPO_DIR/bin/v3c" ]] +} diff --git a/@ether/library/Language/Virgil/install.sh b/@ether/library/Language/Virgil/install.sh new file mode 100755 index 00000000..77c8792f --- /dev/null +++ b/@ether/library/Language/Virgil/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Virgil - https://github.com/titzer/virgil +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/titzer/virgil" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/titzer/virgil.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make +mkdir -p "$HOME/.local/bin" +ln -sf "$REPO_DIR/bin/v3c" "$HOME/.local/bin/v3c" +ln -sf "$REPO_DIR/bin/v3i" "$HOME/.local/bin/v3i" diff --git a/@ether/library/Language/Virgil/repl.sh b/@ether/library/Language/Virgil/repl.sh new file mode 100755 index 00000000..909c8e87 --- /dev/null +++ b/@ether/library/Language/Virgil/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Virgil does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Virgil/run.sh b/@ether/library/Language/Virgil/run.sh new file mode 100755 index 00000000..45c60c11 --- /dev/null +++ b/@ether/library/Language/Virgil/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v v3i >/dev/null 2>&1; then + exec v3i "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/titzer/virgil" + exec "$REPO_DIR/bin/v3i" "$1" +fi diff --git a/@ether/library/Language/VisualBasic/check.sh b/@ether/library/Language/VisualBasic/check.sh new file mode 100755 index 00000000..e922ff5b --- /dev/null +++ b/@ether/library/Language/VisualBasic/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v dotnet >/dev/null 2>&1 diff --git a/@ether/library/Language/VisualBasic/install.sh b/@ether/library/Language/VisualBasic/install.sh new file mode 100755 index 00000000..fa945b9e --- /dev/null +++ b/@ether/library/Language/VisualBasic/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Visual Basic .NET requires the .NET SDK +# https://learn.microsoft.com/en-us/dotnet/core/install/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask dotnet-sdk +elif command -v apt-get >/dev/null 2>&1; then + # Microsoft official repo + curl -fsSL https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -o /tmp/packages-microsoft-prod.deb + sudo dpkg -i /tmp/packages-microsoft-prod.deb + sudo apt-get update && sudo apt-get install -y dotnet-sdk-8.0 + rm -f /tmp/packages-microsoft-prod.deb +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y dotnet-sdk-8.0 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm dotnet-sdk +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/VisualBasic/repl.sh b/@ether/library/Language/VisualBasic/repl.sh new file mode 100755 index 00000000..dd66801d --- /dev/null +++ b/@ether/library/Language/VisualBasic/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Visual Basic .NET does not provide a standalone REPL." >&2 +exit 1 diff --git a/@ether/library/Language/VisualBasic/run.sh b/@ether/library/Language/VisualBasic/run.sh new file mode 100755 index 00000000..1257f91c --- /dev/null +++ b/@ether/library/Language/VisualBasic/run.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +if [[ -d "$file" ]]; then + cd "$file" && dotnet run +else + TMPDIR=$(mktemp -d) + dotnet new console --language VB -o "$TMPDIR" --force >/dev/null + cp "$file" "$TMPDIR/Program.vb" + cd "$TMPDIR" && dotnet run + rm -rf "$TMPDIR" +fi diff --git a/@ether/library/Language/Vyper/check.sh b/@ether/library/Language/Vyper/check.sh new file mode 100755 index 00000000..3023c409 --- /dev/null +++ b/@ether/library/Language/Vyper/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v vyper >/dev/null 2>&1 diff --git a/@ether/library/Language/Vyper/install.sh b/@ether/library/Language/Vyper/install.sh new file mode 100755 index 00000000..96a92899 --- /dev/null +++ b/@ether/library/Language/Vyper/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Vyper from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/vyperlang/vyper" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/vyperlang/vyper.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install -e . + exit 0 +fi +# Official: https://docs.vyperlang.org/en/stable/installing-vyper.html +pip install vyper diff --git a/@ether/library/Language/Vyper/repl.sh b/@ether/library/Language/Vyper/repl.sh new file mode 100755 index 00000000..64dfca2c --- /dev/null +++ b/@ether/library/Language/Vyper/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Vyper does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Vyper/run.sh b/@ether/library/Language/Vyper/run.sh new file mode 100755 index 00000000..f5e9c190 --- /dev/null +++ b/@ether/library/Language/Vyper/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec vyper "$1" diff --git a/@ether/library/Language/WGSL/check.sh b/@ether/library/Language/WGSL/check.sh new file mode 100755 index 00000000..f7fdb40f --- /dev/null +++ b/@ether/library/Language/WGSL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v naga >/dev/null 2>&1 diff --git a/@ether/library/Language/WGSL/install.sh b/@ether/library/Language/WGSL/install.sh new file mode 100755 index 00000000..17a07f5b --- /dev/null +++ b/@ether/library/Language/WGSL/install.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +# WGSL (WebGPU Shading Language) - shading language for WebGPU +# naga CLI can validate/translate WGSL +# https://www.w3.org/TR/WGSL/ +cargo install naga-cli 2>/dev/null || { + echo "Install Rust/Cargo first, then: cargo install naga-cli" >&2 + echo "WGSL is primarily used in browsers via the WebGPU API." >&2 + exit 1 +} diff --git a/@ether/library/Language/WGSL/repl.sh b/@ether/library/Language/WGSL/repl.sh new file mode 100755 index 00000000..8aa73885 --- /dev/null +++ b/@ether/library/Language/WGSL/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "WGSL does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/WGSL/run.sh b/@ether/library/Language/WGSL/run.sh new file mode 100755 index 00000000..69bcedcc --- /dev/null +++ b/@ether/library/Language/WGSL/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# WGSL is a shader language; naga can validate it +exec naga "$1" diff --git a/@ether/library/Language/Waldmeister/check.sh b/@ether/library/Language/Waldmeister/check.sh new file mode 100755 index 00000000..7dc49b1c --- /dev/null +++ b/@ether/library/Language/Waldmeister/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v waldmeister >/dev/null 2>&1 diff --git a/@ether/library/Language/Waldmeister/install.sh b/@ether/library/Language/Waldmeister/install.sh new file mode 100755 index 00000000..3166d1c9 --- /dev/null +++ b/@ether/library/Language/Waldmeister/install.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# Waldmeister - equational theorem prover +# https://www.waldmeister.org/ +echo "Waldmeister must be downloaded from: https://www.waldmeister.org/" +echo "Download the binary distribution for your platform." +mkdir -p "$HOME/.local/bin" +OS="$(uname -s)" +ARCH="$(uname -m)" +if [[ "$OS" == "Linux" && "$ARCH" == "x86_64" ]]; then + curl -fsSL "https://www.waldmeister.org/download/waldmeister-linux-x86_64" -o "$HOME/.local/bin/waldmeister" 2>/dev/null && \ + chmod +x "$HOME/.local/bin/waldmeister" || { + echo "Could not auto-download. Visit https://www.waldmeister.org/" >&2 + exit 1 + } +else + echo "Visit https://www.waldmeister.org/ for your platform." >&2 + exit 1 +fi diff --git a/@ether/library/Language/Waldmeister/repl.sh b/@ether/library/Language/Waldmeister/repl.sh new file mode 100755 index 00000000..287f95b2 --- /dev/null +++ b/@ether/library/Language/Waldmeister/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Waldmeister does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Waldmeister/run.sh b/@ether/library/Language/Waldmeister/run.sh new file mode 100755 index 00000000..b54f27a1 --- /dev/null +++ b/@ether/library/Language/Waldmeister/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec waldmeister "$1" diff --git a/@ether/library/Language/Wasp/check.sh b/@ether/library/Language/Wasp/check.sh new file mode 100755 index 00000000..3469b335 --- /dev/null +++ b/@ether/library/Language/Wasp/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v wasp >/dev/null 2>&1 diff --git a/@ether/library/Language/Wasp/install.sh b/@ether/library/Language/Wasp/install.sh new file mode 100755 index 00000000..ec921119 --- /dev/null +++ b/@ether/library/Language/Wasp/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Wasp from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/wasp-lang/wasp" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/wasp-lang/wasp.git "$REPO_DIR" + fi + cd "$REPO_DIR/waspc" + command -v stack >/dev/null 2>&1 || { echo "Haskell Stack required." >&2; exit 1; } + stack build && stack install + exit 0 +fi +# Official: https://wasp-lang.dev/docs/quick-start +curl -sSL https://get.wasp-lang.dev/installer.sh | sh diff --git a/@ether/library/Language/Wasp/repl.sh b/@ether/library/Language/Wasp/repl.sh new file mode 100755 index 00000000..fca1c652 --- /dev/null +++ b/@ether/library/Language/Wasp/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Wasp does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Wasp/run.sh b/@ether/library/Language/Wasp/run.sh new file mode 100755 index 00000000..4b4c9da5 --- /dev/null +++ b/@ether/library/Language/Wasp/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ -d "$1" ]]; then + cd "$1" && wasp start +else + echo "Wasp expects a project directory, not a single file." >&2 + exit 1 +fi diff --git a/@ether/library/Language/WebAssembly/check.sh b/@ether/library/Language/WebAssembly/check.sh new file mode 100755 index 00000000..662b3af5 --- /dev/null +++ b/@ether/library/Language/WebAssembly/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v wasmtime >/dev/null 2>&1 || command -v wasm-interp >/dev/null 2>&1 diff --git a/@ether/library/Language/WebAssembly/install.sh b/@ether/library/Language/WebAssembly/install.sh new file mode 100755 index 00000000..e07e2245 --- /dev/null +++ b/@ether/library/Language/WebAssembly/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +# WebAssembly tooling: wabt (WebAssembly Binary Toolkit) + wasmtime runtime +# https://webassembly.org/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install wabt wasmtime +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y wabt + # wasmtime via official installer + curl https://wasmtime.dev/install.sh -sSf | bash +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y wabt + curl https://wasmtime.dev/install.sh -sSf | bash +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm wabt wasmtime +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/WebAssembly/repl.sh b/@ether/library/Language/WebAssembly/repl.sh new file mode 100755 index 00000000..3a3df497 --- /dev/null +++ b/@ether/library/Language/WebAssembly/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "WebAssembly does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/WebAssembly/run.sh b/@ether/library/Language/WebAssembly/run.sh new file mode 100755 index 00000000..0a102b3c --- /dev/null +++ b/@ether/library/Language/WebAssembly/run.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +FILE="$1" +if [[ "$FILE" == *.wat ]]; then + # Convert WAT to WASM first + wat2wasm "$FILE" -o /tmp/wasm_out.wasm + exec wasmtime /tmp/wasm_out.wasm +else + exec wasmtime "$FILE" +fi diff --git a/@ether/library/Language/WebPPL/check.sh b/@ether/library/Language/WebPPL/check.sh new file mode 100755 index 00000000..11976256 --- /dev/null +++ b/@ether/library/Language/WebPPL/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v webppl >/dev/null 2>&1 diff --git a/@ether/library/Language/WebPPL/install.sh b/@ether/library/Language/WebPPL/install.sh new file mode 100755 index 00000000..5be3eca8 --- /dev/null +++ b/@ether/library/Language/WebPPL/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +# WebPPL - probabilistic programming language - http://webppl.org/ +# Requires Node.js +command -v node >/dev/null 2>&1 || { echo "Node.js is required for WebPPL." >&2; exit 1; } +npm install -g webppl diff --git a/@ether/library/Language/WebPPL/repl.sh b/@ether/library/Language/WebPPL/repl.sh new file mode 100755 index 00000000..a852a0ce --- /dev/null +++ b/@ether/library/Language/WebPPL/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec webppl diff --git a/@ether/library/Language/WebPPL/run.sh b/@ether/library/Language/WebPPL/run.sh new file mode 100755 index 00000000..ff6d791e --- /dev/null +++ b/@ether/library/Language/WebPPL/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec webppl "$1" diff --git a/@ether/library/Language/Whenever/check.sh b/@ether/library/Language/Whenever/check.sh new file mode 100755 index 00000000..c1dd7aa1 --- /dev/null +++ b/@ether/library/Language/Whenever/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v whenever >/dev/null 2>&1 || python3 -c "import whenever_lang" 2>/dev/null diff --git a/@ether/library/Language/Whenever/install.sh b/@ether/library/Language/Whenever/install.sh new file mode 100755 index 00000000..6d42e06d --- /dev/null +++ b/@ether/library/Language/Whenever/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# Whenever - esoteric language where execution order is random +# https://esolangs.org/wiki/Whenever +# A Python implementation exists +pip install whenever-lang 2>/dev/null || { + echo "No standard package. See https://esolangs.org/wiki/Whenever for interpreters." >&2 + exit 1 +} diff --git a/@ether/library/Language/Whenever/repl.sh b/@ether/library/Language/Whenever/repl.sh new file mode 100755 index 00000000..9c78079c --- /dev/null +++ b/@ether/library/Language/Whenever/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Whenever does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Whenever/run.sh b/@ether/library/Language/Whenever/run.sh new file mode 100755 index 00000000..586b1d9e --- /dev/null +++ b/@ether/library/Language/Whenever/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v whenever >/dev/null 2>&1; then + exec whenever "$1" +else + exec python3 -m whenever_lang "$1" +fi diff --git a/@ether/library/Language/Whiley/check.sh b/@ether/library/Language/Whiley/check.sh new file mode 100755 index 00000000..623bcc54 --- /dev/null +++ b/@ether/library/Language/Whiley/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v wy >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Whiley/WhileyCompiler" + [[ -x "$REPO_DIR/bin/wy" ]] +} diff --git a/@ether/library/Language/Whiley/install.sh b/@ether/library/Language/Whiley/install.sh new file mode 100755 index 00000000..a7b24f46 --- /dev/null +++ b/@ether/library/Language/Whiley/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Whiley - https://whiley.org/ +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Whiley/WhileyCompiler" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Whiley/WhileyCompiler.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v ant >/dev/null 2>&1 || { echo "Apache Ant required." >&2; exit 1; } +ant build +mkdir -p "$HOME/.local/bin" +ln -sf "$REPO_DIR/bin/wy" "$HOME/.local/bin/wy" diff --git a/@ether/library/Language/Whiley/repl.sh b/@ether/library/Language/Whiley/repl.sh new file mode 100755 index 00000000..8d265e4f --- /dev/null +++ b/@ether/library/Language/Whiley/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Whiley does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Whiley/run.sh b/@ether/library/Language/Whiley/run.sh new file mode 100755 index 00000000..543f5d77 --- /dev/null +++ b/@ether/library/Language/Whiley/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v wy >/dev/null 2>&1; then + exec wy run "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Whiley/WhileyCompiler" + exec "$REPO_DIR/bin/wy" run "$1" +fi diff --git a/@ether/library/Language/Whitespace/check.sh b/@ether/library/Language/Whitespace/check.sh new file mode 100755 index 00000000..63dce69b --- /dev/null +++ b/@ether/library/Language/Whitespace/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v wspace >/dev/null 2>&1 || command -v whitespace >/dev/null 2>&1 diff --git a/@ether/library/Language/Whitespace/install.sh b/@ether/library/Language/Whitespace/install.sh new file mode 100755 index 00000000..0c53e4b4 --- /dev/null +++ b/@ether/library/Language/Whitespace/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +# Whitespace - esoteric language using only spaces, tabs, and newlines +# https://esolangs.org/wiki/Whitespace +# wspace is a Haskell interpreter +if command -v cabal >/dev/null 2>&1; then + cabal update && cabal install wspace +elif command -v stack >/dev/null 2>&1; then + stack install wspace +else + # Use a Python implementation + pip install whitespace +fi diff --git a/@ether/library/Language/Whitespace/repl.sh b/@ether/library/Language/Whitespace/repl.sh new file mode 100755 index 00000000..bf6164fa --- /dev/null +++ b/@ether/library/Language/Whitespace/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Whitespace does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Whitespace/run.sh b/@ether/library/Language/Whitespace/run.sh new file mode 100755 index 00000000..34e6b5aa --- /dev/null +++ b/@ether/library/Language/Whitespace/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v wspace >/dev/null 2>&1; then + exec wspace "$1" +elif command -v whitespace >/dev/null 2>&1; then + exec whitespace "$1" +else + echo "No Whitespace interpreter found." >&2; exit 1 +fi diff --git a/@ether/library/Language/Why3/check.sh b/@ether/library/Language/Why3/check.sh new file mode 100755 index 00000000..386e645b --- /dev/null +++ b/@ether/library/Language/Why3/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v why3 >/dev/null 2>&1 diff --git a/@ether/library/Language/Why3/install.sh b/@ether/library/Language/Why3/install.sh new file mode 100755 index 00000000..d1b2c886 --- /dev/null +++ b/@ether/library/Language/Why3/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +# Why3 - deductive program verification platform +# https://www.why3.org/ +if [[ "$(uname)" == "Darwin" ]]; then + brew install why3 || opam install why3 +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y why3 +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y why3 || opam install why3 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm why3 || opam install why3 +else + # Fallback: install via opam + command -v opam >/dev/null 2>&1 || { echo "OPAM required to install Why3." >&2; exit 1; } + opam install why3 +fi diff --git a/@ether/library/Language/Why3/repl.sh b/@ether/library/Language/Why3/repl.sh new file mode 100755 index 00000000..19ea0cb9 --- /dev/null +++ b/@ether/library/Language/Why3/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec why3 ide diff --git a/@ether/library/Language/Why3/run.sh b/@ether/library/Language/Why3/run.sh new file mode 100755 index 00000000..332858f0 --- /dev/null +++ b/@ether/library/Language/Why3/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec why3 prove "$1" diff --git a/@ether/library/Language/WolframLanguage/check.sh b/@ether/library/Language/WolframLanguage/check.sh new file mode 100755 index 00000000..fbcaf33d --- /dev/null +++ b/@ether/library/Language/WolframLanguage/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v wolframscript >/dev/null 2>&1 || command -v math >/dev/null 2>&1 || command -v wolfram >/dev/null 2>&1 diff --git a/@ether/library/Language/WolframLanguage/install.sh b/@ether/library/Language/WolframLanguage/install.sh new file mode 100755 index 00000000..ca124d53 --- /dev/null +++ b/@ether/library/Language/WolframLanguage/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +# Wolfram Language / Mathematica +# https://www.wolfram.com/engine/ (free for developers) +# The Wolfram Engine can be installed for non-commercial use +echo "Wolfram Language requires a license." +echo "Free Wolfram Engine: https://www.wolfram.com/engine/" +if [[ "$(uname)" == "Darwin" ]]; then + brew install --cask wolfram-engine 2>/dev/null || { + echo "Download from: https://www.wolfram.com/engine/" >&2 + exit 1 + } +else + echo "Download from: https://www.wolfram.com/engine/" >&2 + echo "Or install Mathematica from: https://www.wolfram.com/mathematica/" >&2 + exit 1 +fi diff --git a/@ether/library/Language/WolframLanguage/repl.sh b/@ether/library/Language/WolframLanguage/repl.sh new file mode 100755 index 00000000..3296c1ea --- /dev/null +++ b/@ether/library/Language/WolframLanguage/repl.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v wolframscript >/dev/null 2>&1; then + exec wolframscript +elif command -v wolfram >/dev/null 2>&1; then + exec wolfram +else + exec math +fi diff --git a/@ether/library/Language/WolframLanguage/run.sh b/@ether/library/Language/WolframLanguage/run.sh new file mode 100755 index 00000000..4dfcb675 --- /dev/null +++ b/@ether/library/Language/WolframLanguage/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec wolframscript -file "$1" diff --git a/@ether/library/Language/Wren/check.sh b/@ether/library/Language/Wren/check.sh new file mode 100755 index 00000000..d008d409 --- /dev/null +++ b/@ether/library/Language/Wren/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v wren >/dev/null 2>&1 || command -v wren_cli >/dev/null 2>&1 diff --git a/@ether/library/Language/Wren/install.sh b/@ether/library/Language/Wren/install.sh new file mode 100755 index 00000000..3cf4fd26 --- /dev/null +++ b/@ether/library/Language/Wren/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Wren - https://wren.io/ +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/wren-lang/wren" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/wren-lang/wren.git "$REPO_DIR" +fi +cd "$REPO_DIR" +make +mkdir -p "$HOME/.local/bin" +cp bin/wren "$HOME/.local/bin/" 2>/dev/null || cp wren "$HOME/.local/bin/" 2>/dev/null || true diff --git a/@ether/library/Language/Wren/repl.sh b/@ether/library/Language/Wren/repl.sh new file mode 100755 index 00000000..f2a6552e --- /dev/null +++ b/@ether/library/Language/Wren/repl.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v wren_cli >/dev/null 2>&1; then + exec wren_cli +elif command -v wren >/dev/null 2>&1; then + exec wren +else + echo "No Wren interpreter found." >&2; exit 1 +fi diff --git a/@ether/library/Language/Wren/run.sh b/@ether/library/Language/Wren/run.sh new file mode 100755 index 00000000..6b589e9b --- /dev/null +++ b/@ether/library/Language/Wren/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v wren_cli >/dev/null 2>&1; then + exec wren_cli "$1" +elif command -v wren >/dev/null 2>&1; then + exec wren "$1" +else + echo "No Wren interpreter found." >&2; exit 1 +fi diff --git a/@ether/library/Language/X86/check.sh b/@ether/library/Language/X86/check.sh new file mode 100755 index 00000000..c0fae942 --- /dev/null +++ b/@ether/library/Language/X86/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nasm >/dev/null 2>&1 || command -v as >/dev/null 2>&1 diff --git a/@ether/library/Language/X86/install.sh b/@ether/library/Language/X86/install.sh new file mode 100755 index 00000000..99c600de --- /dev/null +++ b/@ether/library/Language/X86/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# x86 Assembly - requires NASM or GAS (GNU Assembler) +if [[ "$(uname)" == "Darwin" ]]; then + brew install nasm +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y nasm gcc +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y nasm gcc +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm nasm gcc +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/X86/repl.sh b/@ether/library/Language/X86/repl.sh new file mode 100755 index 00000000..732a2ba5 --- /dev/null +++ b/@ether/library/Language/X86/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "x86 Assembly does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/X86/run.sh b/@ether/library/Language/X86/run.sh new file mode 100755 index 00000000..fab03b79 --- /dev/null +++ b/@ether/library/Language/X86/run.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +FILE="$1" +BASENAME="$(basename "$FILE" .asm)" +nasm -f elf32 "$FILE" -o "/tmp/${BASENAME}.o" && \ + ld -m elf_i386 "/tmp/${BASENAME}.o" -o "/tmp/${BASENAME}" && \ + "/tmp/${BASENAME}" diff --git a/@ether/library/Language/X8664Assembly/check.sh b/@ether/library/Language/X8664Assembly/check.sh new file mode 100755 index 00000000..c0fae942 --- /dev/null +++ b/@ether/library/Language/X8664Assembly/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v nasm >/dev/null 2>&1 || command -v as >/dev/null 2>&1 diff --git a/@ether/library/Language/X8664Assembly/install.sh b/@ether/library/Language/X8664Assembly/install.sh new file mode 100755 index 00000000..efff5fa2 --- /dev/null +++ b/@ether/library/Language/X8664Assembly/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# x86-64 Assembly - requires NASM or GAS (GNU Assembler) +if [[ "$(uname)" == "Darwin" ]]; then + brew install nasm +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y nasm gcc +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y nasm gcc +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm nasm gcc +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/X8664Assembly/repl.sh b/@ether/library/Language/X8664Assembly/repl.sh new file mode 100755 index 00000000..f1d8dfa5 --- /dev/null +++ b/@ether/library/Language/X8664Assembly/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "x86-64 Assembly does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/X8664Assembly/run.sh b/@ether/library/Language/X8664Assembly/run.sh new file mode 100755 index 00000000..ee016a90 --- /dev/null +++ b/@ether/library/Language/X8664Assembly/run.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +FILE="$1" +BASENAME="$(basename "$FILE" .asm)" +if [[ "$(uname)" == "Darwin" ]]; then + nasm -f macho64 "$FILE" -o "/tmp/${BASENAME}.o" && \ + ld -macosx_version_min 10.7 -lSystem "/tmp/${BASENAME}.o" -o "/tmp/${BASENAME}" && \ + "/tmp/${BASENAME}" +else + nasm -f elf64 "$FILE" -o "/tmp/${BASENAME}.o" && \ + ld "/tmp/${BASENAME}.o" -o "/tmp/${BASENAME}" && \ + "/tmp/${BASENAME}" +fi diff --git a/@ether/library/Language/XML/check.sh b/@ether/library/Language/XML/check.sh new file mode 100755 index 00000000..51e6bc62 --- /dev/null +++ b/@ether/library/Language/XML/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# XML is a data format; always available +exit 0 diff --git a/@ether/library/Language/XML/install.sh b/@ether/library/Language/XML/install.sh new file mode 100755 index 00000000..2ad37ab0 --- /dev/null +++ b/@ether/library/Language/XML/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# XML is a markup format; no installation required. +# xmllint is commonly available for validation. +if [[ "$(uname)" == "Darwin" ]]; then + # libxml2 (xmllint) is preinstalled on macOS + true +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y libxml2-utils +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y libxml2 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm libxml2 +fi diff --git a/@ether/library/Language/XML/repl.sh b/@ether/library/Language/XML/repl.sh new file mode 100755 index 00000000..2e730032 --- /dev/null +++ b/@ether/library/Language/XML/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "XML is a data format and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/XML/run.sh b/@ether/library/Language/XML/run.sh new file mode 100755 index 00000000..1f7c816d --- /dev/null +++ b/@ether/library/Language/XML/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$1" diff --git a/@ether/library/Language/XPath/check.sh b/@ether/library/Language/XPath/check.sh new file mode 100755 index 00000000..a5d8e3c4 --- /dev/null +++ b/@ether/library/Language/XPath/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v xmllint >/dev/null 2>&1 diff --git a/@ether/library/Language/XPath/install.sh b/@ether/library/Language/XPath/install.sh new file mode 100755 index 00000000..c6a9744a --- /dev/null +++ b/@ether/library/Language/XPath/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# XPath is a query language for XML; xmllint supports it +# https://www.w3.org/TR/xpath/ +if [[ "$(uname)" == "Darwin" ]]; then + # xmllint preinstalled on macOS + true +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y libxml2-utils +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y libxml2 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm libxml2 +fi diff --git a/@ether/library/Language/XPath/repl.sh b/@ether/library/Language/XPath/repl.sh new file mode 100755 index 00000000..e8eec012 --- /dev/null +++ b/@ether/library/Language/XPath/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec xmllint --shell /dev/stdin diff --git a/@ether/library/Language/XPath/run.sh b/@ether/library/Language/XPath/run.sh new file mode 100755 index 00000000..8070ec9c --- /dev/null +++ b/@ether/library/Language/XPath/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# XPath expressions are used against XML documents with xmllint +exec xmllint --xpath "$(cat "$1")" /dev/stdin diff --git a/@ether/library/Language/XQuery/check.sh b/@ether/library/Language/XQuery/check.sh new file mode 100755 index 00000000..063b8488 --- /dev/null +++ b/@ether/library/Language/XQuery/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v basex >/dev/null 2>&1 diff --git a/@ether/library/Language/XQuery/install.sh b/@ether/library/Language/XQuery/install.sh new file mode 100755 index 00000000..84cbd405 --- /dev/null +++ b/@ether/library/Language/XQuery/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# XQuery - query language for XML +# https://www.w3.org/TR/xquery/ +# BaseX is a popular open-source XQuery processor +if [[ "$(uname)" == "Darwin" ]]; then + brew install basex +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y basex +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y basex +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm basex +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/XQuery/repl.sh b/@ether/library/Language/XQuery/repl.sh new file mode 100755 index 00000000..5ee7facf --- /dev/null +++ b/@ether/library/Language/XQuery/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec basex diff --git a/@ether/library/Language/XQuery/run.sh b/@ether/library/Language/XQuery/run.sh new file mode 100755 index 00000000..cc92c76a --- /dev/null +++ b/@ether/library/Language/XQuery/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec basex "$1" diff --git a/@ether/library/Language/Xonsh/check.sh b/@ether/library/Language/Xonsh/check.sh new file mode 100755 index 00000000..3281abec --- /dev/null +++ b/@ether/library/Language/Xonsh/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v xonsh >/dev/null 2>&1 diff --git a/@ether/library/Language/Xonsh/install.sh b/@ether/library/Language/Xonsh/install.sh new file mode 100755 index 00000000..6ad13bca --- /dev/null +++ b/@ether/library/Language/Xonsh/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Xonsh from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/xonsh/xonsh" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/xonsh/xonsh.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install -e . + exit 0 +fi +# Official: https://xon.sh/ +pip install xonsh diff --git a/@ether/library/Language/Xonsh/repl.sh b/@ether/library/Language/Xonsh/repl.sh new file mode 100755 index 00000000..3ed87b19 --- /dev/null +++ b/@ether/library/Language/Xonsh/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec xonsh diff --git a/@ether/library/Language/Xonsh/run.sh b/@ether/library/Language/Xonsh/run.sh new file mode 100755 index 00000000..7a32902d --- /dev/null +++ b/@ether/library/Language/Xonsh/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec xonsh "$1" diff --git a/@ether/library/Language/Xtext/check.sh b/@ether/library/Language/Xtext/check.sh new file mode 100755 index 00000000..b172a851 --- /dev/null +++ b/@ether/library/Language/Xtext/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/eclipse/xtext" +[[ -d "$REPO_DIR" ]] && command -v mvn >/dev/null 2>&1 diff --git a/@ether/library/Language/Xtext/install.sh b/@ether/library/Language/Xtext/install.sh new file mode 100755 index 00000000..38f917fe --- /dev/null +++ b/@ether/library/Language/Xtext/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# Xtext - language development framework (Eclipse) +# https://eclipse.dev/Xtext/ +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/eclipse/xtext" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/eclipse/xtext.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v mvn >/dev/null 2>&1 || { echo "Maven required to build Xtext." >&2; exit 1; } +mvn clean install -DskipTests || true diff --git a/@ether/library/Language/Xtext/repl.sh b/@ether/library/Language/Xtext/repl.sh new file mode 100755 index 00000000..25cdc79e --- /dev/null +++ b/@ether/library/Language/Xtext/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Xtext does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Xtext/run.sh b/@ether/library/Language/Xtext/run.sh new file mode 100755 index 00000000..a6da42fd --- /dev/null +++ b/@ether/library/Language/Xtext/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Xtext is a language development framework, not a standalone runner." >&2 +echo "Use it within Eclipse IDE." >&2 +cat "$1" diff --git a/@ether/library/Language/YAML/check.sh b/@ether/library/Language/YAML/check.sh new file mode 100755 index 00000000..a9065367 --- /dev/null +++ b/@ether/library/Language/YAML/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# YAML is a data format; always available +exit 0 diff --git a/@ether/library/Language/YAML/install.sh b/@ether/library/Language/YAML/install.sh new file mode 100755 index 00000000..70d1ef37 --- /dev/null +++ b/@ether/library/Language/YAML/install.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +# YAML is a data serialization format; no installation required. +# yq can be installed for processing. +if [[ "$(uname)" == "Darwin" ]]; then + brew install yq +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y yq 2>/dev/null || pip install yq +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y yq 2>/dev/null || pip install yq +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm yq 2>/dev/null || pip install yq +fi diff --git a/@ether/library/Language/YAML/repl.sh b/@ether/library/Language/YAML/repl.sh new file mode 100755 index 00000000..2010c46d --- /dev/null +++ b/@ether/library/Language/YAML/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "YAML is a data format and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/YAML/run.sh b/@ether/library/Language/YAML/run.sh new file mode 100755 index 00000000..1f7c816d --- /dev/null +++ b/@ether/library/Language/YAML/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$1" diff --git a/@ether/library/Language/Yatima/check.sh b/@ether/library/Language/Yatima/check.sh new file mode 100755 index 00000000..73a82a7f --- /dev/null +++ b/@ether/library/Language/Yatima/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v yatima >/dev/null 2>&1 diff --git a/@ether/library/Language/Yatima/install.sh b/@ether/library/Language/Yatima/install.sh new file mode 100755 index 00000000..d1e90306 --- /dev/null +++ b/@ether/library/Language/Yatima/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Yatima - https://github.com/argumentcomputer/yatima +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/argumentcomputer/yatima" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/argumentcomputer/yatima.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v cargo >/dev/null 2>&1 || { echo "Rust/Cargo required to build Yatima." >&2; exit 1; } +cargo build --release +mkdir -p "$HOME/.local/bin" +cp target/release/yatima "$HOME/.local/bin/" 2>/dev/null || true diff --git a/@ether/library/Language/Yatima/repl.sh b/@ether/library/Language/Yatima/repl.sh new file mode 100755 index 00000000..bc0a5fa9 --- /dev/null +++ b/@ether/library/Language/Yatima/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec yatima repl diff --git a/@ether/library/Language/Yatima/run.sh b/@ether/library/Language/Yatima/run.sh new file mode 100755 index 00000000..b9f7e809 --- /dev/null +++ b/@ether/library/Language/Yatima/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec yatima check "$1" diff --git a/@ether/library/Language/Z3/check.sh b/@ether/library/Language/Z3/check.sh new file mode 100755 index 00000000..1c8aaf83 --- /dev/null +++ b/@ether/library/Language/Z3/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v z3 >/dev/null 2>&1 diff --git a/@ether/library/Language/Z3/install.sh b/@ether/library/Language/Z3/install.sh new file mode 100755 index 00000000..727a1ed8 --- /dev/null +++ b/@ether/library/Language/Z3/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing Z3 from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/Z3Prover/z3" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/Z3Prover/z3.git "$REPO_DIR" + fi + cd "$REPO_DIR" + python3 scripts/mk_make.py + cd build && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" && sudo make install + exit 0 +fi +# Official: https://github.com/Z3Prover/z3 +if [[ "$(uname)" == "Darwin" ]]; then + brew install z3 +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y z3 +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y z3 +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm z3 +else + pip install z3-solver +fi diff --git a/@ether/library/Language/Z3/repl.sh b/@ether/library/Language/Z3/repl.sh new file mode 100755 index 00000000..8438a414 --- /dev/null +++ b/@ether/library/Language/Z3/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec z3 -in diff --git a/@ether/library/Language/Z3/run.sh b/@ether/library/Language/Z3/run.sh new file mode 100755 index 00000000..e0defafd --- /dev/null +++ b/@ether/library/Language/Z3/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec z3 "$1" diff --git a/@ether/library/Language/ZNotation/check.sh b/@ether/library/Language/ZNotation/check.sh new file mode 100755 index 00000000..7bba7762 --- /dev/null +++ b/@ether/library/Language/ZNotation/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v fuzz >/dev/null 2>&1 || command -v czt >/dev/null 2>&1 diff --git a/@ether/library/Language/ZNotation/install.sh b/@ether/library/Language/ZNotation/install.sh new file mode 100755 index 00000000..7488e555 --- /dev/null +++ b/@ether/library/Language/ZNotation/install.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# Z Notation - formal specification language +# CZT (Community Z Tools) provides tooling +# https://czt.sourceforge.net/ +echo "Z Notation is a formal specification language." +echo "CZT (Community Z Tools) can be downloaded from: https://czt.sourceforge.net/" +echo "Alternatively, use fuzz (Z type checker) if available." +if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y fuzz 2>/dev/null || true +fi diff --git a/@ether/library/Language/ZNotation/repl.sh b/@ether/library/Language/ZNotation/repl.sh new file mode 100755 index 00000000..4ada05cc --- /dev/null +++ b/@ether/library/Language/ZNotation/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Z Notation does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ZNotation/run.sh b/@ether/library/Language/ZNotation/run.sh new file mode 100755 index 00000000..a276e1e8 --- /dev/null +++ b/@ether/library/Language/ZNotation/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v fuzz >/dev/null 2>&1; then + exec fuzz "$1" +elif command -v czt >/dev/null 2>&1; then + exec czt "$1" +else + cat "$1" +fi diff --git a/@ether/library/Language/ZXCalculus.jl/check.sh b/@ether/library/Language/ZXCalculus.jl/check.sh new file mode 100755 index 00000000..3a9ebba6 --- /dev/null +++ b/@ether/library/Language/ZXCalculus.jl/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v julia >/dev/null 2>&1 && julia -e 'using ZXCalculus' 2>/dev/null diff --git a/@ether/library/Language/ZXCalculus.jl/install.sh b/@ether/library/Language/ZXCalculus.jl/install.sh new file mode 100755 index 00000000..dd797591 --- /dev/null +++ b/@ether/library/Language/ZXCalculus.jl/install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +# ZXCalculus.jl - Julia package for ZX-calculus +# https://github.com/QuantumBFS/ZXCalculus.jl +command -v julia >/dev/null 2>&1 || { echo "Julia is required." >&2; exit 1; } +julia -e 'using Pkg; Pkg.add("ZXCalculus")' diff --git a/@ether/library/Language/ZXCalculus.jl/repl.sh b/@ether/library/Language/ZXCalculus.jl/repl.sh new file mode 100755 index 00000000..29079cee --- /dev/null +++ b/@ether/library/Language/ZXCalculus.jl/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec julia -e 'using ZXCalculus; Base.run_main_repl(true, true, true, true, false)' diff --git a/@ether/library/Language/ZXCalculus.jl/run.sh b/@ether/library/Language/ZXCalculus.jl/run.sh new file mode 100755 index 00000000..df6a60d7 --- /dev/null +++ b/@ether/library/Language/ZXCalculus.jl/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec julia "$1" diff --git a/@ether/library/Language/Zenon/check.sh b/@ether/library/Language/Zenon/check.sh new file mode 100755 index 00000000..7a6e9676 --- /dev/null +++ b/@ether/library/Language/Zenon/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v zenon >/dev/null 2>&1 diff --git a/@ether/library/Language/Zenon/install.sh b/@ether/library/Language/Zenon/install.sh new file mode 100755 index 00000000..75318c8b --- /dev/null +++ b/@ether/library/Language/Zenon/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Zenon - automated theorem prover +# https://github.com/zenon-prover/zenon +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zenon-prover/zenon" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/zenon-prover/zenon.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v ocamlfind >/dev/null 2>&1 || command -v ocamlopt >/dev/null 2>&1 || { echo "OCaml required to build Zenon." >&2; exit 1; } +./configure && make +sudo make install || { mkdir -p "$HOME/.local/bin" && cp zenon "$HOME/.local/bin/"; } diff --git a/@ether/library/Language/Zenon/repl.sh b/@ether/library/Language/Zenon/repl.sh new file mode 100755 index 00000000..a17c46e2 --- /dev/null +++ b/@ether/library/Language/Zenon/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Zenon does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Zenon/run.sh b/@ether/library/Language/Zenon/run.sh new file mode 100755 index 00000000..8d504f07 --- /dev/null +++ b/@ether/library/Language/Zenon/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec zenon "$1" diff --git a/@ether/library/Language/ZetaCalculus/check.sh b/@ether/library/Language/ZetaCalculus/check.sh new file mode 100755 index 00000000..cc21cf21 --- /dev/null +++ b/@ether/library/Language/ZetaCalculus/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Zeta Calculus has no standard implementation." >&2 +exit 1 diff --git a/@ether/library/Language/ZetaCalculus/install.sh b/@ether/library/Language/ZetaCalculus/install.sh new file mode 100755 index 00000000..0c962842 --- /dev/null +++ b/@ether/library/Language/ZetaCalculus/install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# Zeta Calculus - theoretical framework +# https://zeta.nicbot.xyz/ +# No standard implementation/package exists +echo "Zeta Calculus is a theoretical framework." +echo "See: https://zeta.nicbot.xyz/ and https://arxiv.org/abs/2303.17399" +echo "No standard package available." >&2 +exit 1 diff --git a/@ether/library/Language/ZetaCalculus/repl.sh b/@ether/library/Language/ZetaCalculus/repl.sh new file mode 100755 index 00000000..c0f5077e --- /dev/null +++ b/@ether/library/Language/ZetaCalculus/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Zeta Calculus does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/ZetaCalculus/run.sh b/@ether/library/Language/ZetaCalculus/run.sh new file mode 100755 index 00000000..16101332 --- /dev/null +++ b/@ether/library/Language/ZetaCalculus/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Zeta Calculus has no standard implementation to run files." >&2 +exit 1 diff --git a/@ether/library/Language/Zig/check.sh b/@ether/library/Language/Zig/check.sh new file mode 100755 index 00000000..1efd65d2 --- /dev/null +++ b/@ether/library/Language/Zig/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v zig >/dev/null 2>&1 diff --git a/@ether/library/Language/Zig/install.sh b/@ether/library/Language/Zig/install.sh new file mode 100755 index 00000000..5d77cc75 --- /dev/null +++ b/@ether/library/Language/Zig/install.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/ziglang/zig" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/ziglang/zig.git "$REPO_DIR" + fi + cd "$REPO_DIR" && mkdir -p build && cd build && cmake .. && make -j"$(nproc)" + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install zig +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm zig +elif command -v snap >/dev/null 2>&1; then + sudo snap install zig --classic --beta +else + echo "Install via snap: sudo snap install zig --classic --beta" >&2 + echo "Or download from https://ziglang.org/download/" >&2 + exit 1 +fi diff --git a/@ether/library/Language/Zig/packages.sh b/@ether/library/Language/Zig/packages.sh new file mode 100755 index 00000000..54da9bf1 --- /dev/null +++ b/@ether/library/Language/Zig/packages.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRIES=( + "https://astrolabe.pm" + "https://github.com/zigtools" +) + +usage() { + echo "Zig Package Registries:" + for url in "${REGISTRIES[@]}"; do echo " $url"; done + echo + echo "Usage: packages.sh {search|info|install} " +} + +cmd_search() { + local q="$1" + echo "https://astrolabe.pm/?q=$q" +} + +cmd_info() { + local pkg="$1" + echo "https://astrolabe.pm/packages/$pkg" +} + +cmd_install() { + local pkg="$1" + echo "Add to build.zig.zon dependencies:" + echo + echo " .dependencies = .{" + echo " .$pkg = .{" + echo " .url = \"https://github.com/OWNER/$pkg/archive/REF.tar.gz\"," + echo " .hash = \"...\"," + echo " }," + echo " }," + echo + echo "Then in build.zig:" + echo " const dep = b.dependency(\"$pkg\", .{});" + echo + echo "Find packages: https://astrolabe.pm/?q=$pkg" +} + +case "${1:-}" in + search) shift; cmd_search "$1" ;; + info) shift; cmd_info "$1" ;; + install) shift; cmd_install "$1" ;; + *) usage ;; +esac diff --git a/@ether/library/Language/Zig/repl.sh b/@ether/library/Language/Zig/repl.sh new file mode 100755 index 00000000..bf344473 --- /dev/null +++ b/@ether/library/Language/Zig/repl.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Zig does not have an interactive REPL." +echo "Use 'zig run ' to execute Zig programs." +echo "Or try: https://zig.godbolt.org/ for online execution." +exit 1 diff --git a/@ether/library/Language/Zig/run.sh b/@ether/library/Language/Zig/run.sh new file mode 100755 index 00000000..ec3ef9a6 --- /dev/null +++ b/@ether/library/Language/Zig/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +file="$1" +if [[ -d "$file" ]]; then + cd "$file" && zig build run +else + zig run "$file" +fi diff --git a/@ether/library/Language/Zipperposition/check.sh b/@ether/library/Language/Zipperposition/check.sh new file mode 100755 index 00000000..da157df9 --- /dev/null +++ b/@ether/library/Language/Zipperposition/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v zipperposition >/dev/null 2>&1 diff --git a/@ether/library/Language/Zipperposition/install.sh b/@ether/library/Language/Zipperposition/install.sh new file mode 100755 index 00000000..03d57971 --- /dev/null +++ b/@ether/library/Language/Zipperposition/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +# Zipperposition - superposition theorem prover +# https://github.com/sneeuwballen/zipperposition +if command -v opam >/dev/null 2>&1; then + opam install zipperposition +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/sneeuwballen/zipperposition" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/sneeuwballen/zipperposition.git "$REPO_DIR" + fi + cd "$REPO_DIR" + command -v opam >/dev/null 2>&1 || { echo "OPAM required to build Zipperposition." >&2; exit 1; } + opam install . --deps-only -y + dune build + dune install +fi diff --git a/@ether/library/Language/Zipperposition/repl.sh b/@ether/library/Language/Zipperposition/repl.sh new file mode 100755 index 00000000..b08e4b9e --- /dev/null +++ b/@ether/library/Language/Zipperposition/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Zipperposition does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/Zipperposition/run.sh b/@ether/library/Language/Zipperposition/run.sh new file mode 100755 index 00000000..fcc2f2b4 --- /dev/null +++ b/@ether/library/Language/Zipperposition/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec zipperposition "$1" diff --git a/@ether/library/Language/Zsh/check.sh b/@ether/library/Language/Zsh/check.sh new file mode 100755 index 00000000..03672793 --- /dev/null +++ b/@ether/library/Language/Zsh/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v zsh >/dev/null 2>&1 diff --git a/@ether/library/Language/Zsh/install.sh b/@ether/library/Language/Zsh/install.sh new file mode 100755 index 00000000..580580d8 --- /dev/null +++ b/@ether/library/Language/Zsh/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + # zsh is the default shell on macOS + brew install zsh 2>/dev/null || true +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y zsh +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y zsh +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm zsh +else + echo "Unsupported package manager." >&2; exit 1 +fi diff --git a/@ether/library/Language/Zsh/repl.sh b/@ether/library/Language/Zsh/repl.sh new file mode 100755 index 00000000..0c695015 --- /dev/null +++ b/@ether/library/Language/Zsh/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec zsh --no-rcs diff --git a/@ether/library/Language/Zsh/run.sh b/@ether/library/Language/Zsh/run.sh new file mode 100755 index 00000000..7053c6bc --- /dev/null +++ b/@ether/library/Language/Zsh/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec zsh "$1" diff --git a/@ether/library/Language/aUI/check.sh b/@ether/library/Language/aUI/check.sh new file mode 100755 index 00000000..fd1e9cbb --- /dev/null +++ b/@ether/library/Language/aUI/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# aUI is a constructed language; no tooling to check +exit 1 diff --git a/@ether/library/Language/aUI/install.sh b/@ether/library/Language/aUI/install.sh new file mode 100755 index 00000000..d32b6438 --- /dev/null +++ b/@ether/library/Language/aUI/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# aUI is a constructed language with no standard tooling or compiler. +echo "aUI is a constructed language. No standard tooling available." diff --git a/@ether/library/Language/aUI/repl.sh b/@ether/library/Language/aUI/repl.sh new file mode 100755 index 00000000..66c16a66 --- /dev/null +++ b/@ether/library/Language/aUI/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "aUI is a constructed language. No REPL available." >&2 +exit 1 diff --git a/@ether/library/Language/aUI/run.sh b/@ether/library/Language/aUI/run.sh new file mode 100755 index 00000000..aa9bad21 --- /dev/null +++ b/@ether/library/Language/aUI/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "aUI is a constructed language with no executable tooling." >&2 +exit 1 diff --git a/@ether/library/Language/bayesloop/check.sh b/@ether/library/Language/bayesloop/check.sh new file mode 100755 index 00000000..423bc104 --- /dev/null +++ b/@ether/library/Language/bayesloop/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import bayesloop" 2>/dev/null diff --git a/@ether/library/Language/bayesloop/install.sh b/@ether/library/Language/bayesloop/install.sh new file mode 100755 index 00000000..55694bd1 --- /dev/null +++ b/@ether/library/Language/bayesloop/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# bayesloop - probabilistic time series analysis +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/christophmark/bayesloop" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/christophmark/bayesloop.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install bayesloop diff --git a/@ether/library/Language/bayesloop/repl.sh b/@ether/library/Language/bayesloop/repl.sh new file mode 100755 index 00000000..14520b57 --- /dev/null +++ b/@ether/library/Language/bayesloop/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Launching Python REPL with bayesloop imported..." +exec python3 -c "import bayesloop; print('bayesloop loaded.'); import code; code.interact(local=dict(bayesloop=bayesloop))" diff --git a/@ether/library/Language/bayesloop/run.sh b/@ether/library/Language/bayesloop/run.sh new file mode 100755 index 00000000..417c42d0 --- /dev/null +++ b/@ether/library/Language/bayesloop/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$1" diff --git a/@ether/library/Language/chimple/check.sh b/@ether/library/Language/chimple/check.sh new file mode 100755 index 00000000..2473440c --- /dev/null +++ b/@ether/library/Language/chimple/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/analog-garage/chimple" +[[ -d "$REPO_DIR" ]] && command -v java >/dev/null 2>&1 diff --git a/@ether/library/Language/chimple/install.sh b/@ether/library/Language/chimple/install.sh new file mode 100755 index 00000000..69cdd5ee --- /dev/null +++ b/@ether/library/Language/chimple/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/analog-garage/chimple" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/analog-garage/chimple.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v gradle >/dev/null 2>&1; then + gradle build +elif [[ -f gradlew ]]; then + ./gradlew build +else + echo "Gradle is required to build chimple." >&2; exit 1 +fi diff --git a/@ether/library/Language/chimple/repl.sh b/@ether/library/Language/chimple/repl.sh new file mode 100755 index 00000000..94c2446a --- /dev/null +++ b/@ether/library/Language/chimple/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "chimple does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/chimple/run.sh b/@ether/library/Language/chimple/run.sh new file mode 100755 index 00000000..7db540ee --- /dev/null +++ b/@ether/library/Language/chimple/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/analog-garage/chimple" +cd "$REPO_DIR" +java -cp "build/libs/*" "$1" diff --git a/@ether/library/Language/clasp/check.sh b/@ether/library/Language/clasp/check.sh new file mode 100755 index 00000000..6ebadd6f --- /dev/null +++ b/@ether/library/Language/clasp/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v clasp >/dev/null 2>&1 diff --git a/@ether/library/Language/clasp/install.sh b/@ether/library/Language/clasp/install.sh new file mode 100755 index 00000000..c50dfc16 --- /dev/null +++ b/@ether/library/Language/clasp/install.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$(uname)" == "Darwin" ]]; then + brew install clasp-solver || brew install clingo +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y clasp || sudo apt-get install -y gringo clasp +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y clasp || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/potassco/clasp" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/potassco/clasp.git "$REPO_DIR" + fi + cd "$REPO_DIR" + mkdir -p build && cd build + cmake .. && make -j"$(nproc)" + sudo make install + } +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm clasp +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/potassco/clasp" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/potassco/clasp.git "$REPO_DIR" + fi + cd "$REPO_DIR" + mkdir -p build && cd build + cmake .. && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" + sudo make install +fi diff --git a/@ether/library/Language/clasp/repl.sh b/@ether/library/Language/clasp/repl.sh new file mode 100755 index 00000000..c4227099 --- /dev/null +++ b/@ether/library/Language/clasp/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "clasp is a solver and does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/clasp/run.sh b/@ether/library/Language/clasp/run.sh new file mode 100755 index 00000000..439c1674 --- /dev/null +++ b/@ether/library/Language/clasp/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec clasp "$1" diff --git a/@ether/library/Language/cubicaltt/check.sh b/@ether/library/Language/cubicaltt/check.sh new file mode 100755 index 00000000..c854e893 --- /dev/null +++ b/@ether/library/Language/cubicaltt/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v cubical >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mortberg/cubicaltt" + [[ -d "$REPO_DIR" ]] +} diff --git a/@ether/library/Language/cubicaltt/install.sh b/@ether/library/Language/cubicaltt/install.sh new file mode 100755 index 00000000..d5420ecc --- /dev/null +++ b/@ether/library/Language/cubicaltt/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mortberg/cubicaltt" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/mortberg/cubicaltt.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v cabal >/dev/null 2>&1; then + cabal update && cabal build +elif command -v stack >/dev/null 2>&1; then + stack build +else + echo "Install GHC/cabal or stack first." >&2; exit 1 +fi diff --git a/@ether/library/Language/cubicaltt/repl.sh b/@ether/library/Language/cubicaltt/repl.sh new file mode 100755 index 00000000..cae74c58 --- /dev/null +++ b/@ether/library/Language/cubicaltt/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "cubicaltt does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/cubicaltt/run.sh b/@ether/library/Language/cubicaltt/run.sh new file mode 100755 index 00000000..97b2b552 --- /dev/null +++ b/@ether/library/Language/cubicaltt/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v cubical >/dev/null 2>&1; then + exec cubical "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mortberg/cubicaltt" + cd "$REPO_DIR" + cabal run cubical -- "$1" +fi diff --git a/@ether/library/Language/diffSAT/check.sh b/@ether/library/Language/diffSAT/check.sh new file mode 100755 index 00000000..3599b6be --- /dev/null +++ b/@ether/library/Language/diffSAT/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/MatthiasNickworX/diffSAT" +ls "$REPO_DIR"/target/scala-*/diffSAT*.jar >/dev/null 2>&1 || command -v diffSAT >/dev/null 2>&1 diff --git a/@ether/library/Language/diffSAT/install.sh b/@ether/library/Language/diffSAT/install.sh new file mode 100755 index 00000000..55f22615 --- /dev/null +++ b/@ether/library/Language/diffSAT/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install diffSAT - https://github.com/MatthiasNickworX/diffSAT (Scala-based SAT solver) +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/MatthiasNickworX/diffSAT" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/MatthiasNickworX/diffSAT.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v sbt >/dev/null 2>&1; then + sbt assembly +else + echo "sbt (Scala Build Tool) is required. Install sbt first." >&2; exit 1 +fi diff --git a/@ether/library/Language/diffSAT/repl.sh b/@ether/library/Language/diffSAT/repl.sh new file mode 100755 index 00000000..f7113de9 --- /dev/null +++ b/@ether/library/Language/diffSAT/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "diffSAT has no interactive REPL. Use: diffSAT " >&2 +exit 1 diff --git a/@ether/library/Language/diffSAT/run.sh b/@ether/library/Language/diffSAT/run.sh new file mode 100755 index 00000000..be6a5e25 --- /dev/null +++ b/@ether/library/Language/diffSAT/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/MatthiasNickworX/diffSAT" +JAR=$(ls "$REPO_DIR"/target/scala-*/diffSAT*.jar 2>/dev/null | head -1) +if [[ -n "${JAR:-}" ]]; then + exec java -jar "$JAR" "$1" +else + exec diffSAT "$1" +fi diff --git a/@ether/library/Language/dimple/check.sh b/@ether/library/Language/dimple/check.sh new file mode 100755 index 00000000..547b17f1 --- /dev/null +++ b/@ether/library/Language/dimple/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/analog-garage/dimple" +[[ -d "$REPO_DIR/build" ]] || command -v dimple >/dev/null 2>&1 diff --git a/@ether/library/Language/dimple/install.sh b/@ether/library/Language/dimple/install.sh new file mode 100755 index 00000000..28e08c60 --- /dev/null +++ b/@ether/library/Language/dimple/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +# Install dimple - https://github.com/analog-garage/dimple +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/analog-garage/dimple" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/analog-garage/dimple.git "$REPO_DIR" +fi +cd "$REPO_DIR" +if command -v gradle >/dev/null 2>&1; then + gradle build -x test +elif [[ -f ./gradlew ]]; then + ./gradlew build -x test +else + echo "Gradle is required to build dimple." >&2; exit 1 +fi diff --git a/@ether/library/Language/dimple/repl.sh b/@ether/library/Language/dimple/repl.sh new file mode 100755 index 00000000..bd98c0e8 --- /dev/null +++ b/@ether/library/Language/dimple/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "dimple has no interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/dimple/run.sh b/@ether/library/Language/dimple/run.sh new file mode 100755 index 00000000..12a87023 --- /dev/null +++ b/@ether/library/Language/dimple/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/analog-garage/dimple" +exec java -cp "$REPO_DIR/build/libs/*" com.analog.lyric.dimple.DimpleMain "$1" diff --git a/@ether/library/Language/greta/check.sh b/@ether/library/Language/greta/check.sh new file mode 100755 index 00000000..1b459e46 --- /dev/null +++ b/@ether/library/Language/greta/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v Rscript >/dev/null 2>&1 && Rscript -e 'library(greta)' >/dev/null 2>&1 diff --git a/@ether/library/Language/greta/install.sh b/@ether/library/Language/greta/install.sh new file mode 100755 index 00000000..ccee8468 --- /dev/null +++ b/@ether/library/Language/greta/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing greta from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/greta-dev/greta" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/greta-dev/greta.git "$REPO_DIR" + fi + cd "$REPO_DIR" && Rscript -e "devtools::install('.')" + exit 0 +fi +# Install greta R package from CRAN +command -v Rscript >/dev/null 2>&1 || { echo "R is required. Install R first." >&2; exit 1; } +Rscript -e 'install.packages("greta", repos="https://cloud.r-project.org")' diff --git a/@ether/library/Language/greta/repl.sh b/@ether/library/Language/greta/repl.sh new file mode 100755 index 00000000..b991ab1f --- /dev/null +++ b/@ether/library/Language/greta/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec R -e 'library(greta)' diff --git a/@ether/library/Language/greta/run.sh b/@ether/library/Language/greta/run.sh new file mode 100755 index 00000000..81226edb --- /dev/null +++ b/@ether/library/Language/greta/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec Rscript "$1" diff --git a/@ether/library/Language/iCNF/check.sh b/@ether/library/Language/iCNF/check.sh new file mode 100755 index 00000000..5e6cc999 --- /dev/null +++ b/@ether/library/Language/iCNF/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# iCNF is a data format; always available. +exit 0 diff --git a/@ether/library/Language/iCNF/install.sh b/@ether/library/Language/iCNF/install.sh new file mode 100755 index 00000000..e9749cc7 --- /dev/null +++ b/@ether/library/Language/iCNF/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# iCNF is a data format for incremental CNF (SAT solver input). No installation required. +echo "iCNF is a data format. No installation required." diff --git a/@ether/library/Language/iCNF/repl.sh b/@ether/library/Language/iCNF/repl.sh new file mode 100755 index 00000000..463f58d5 --- /dev/null +++ b/@ether/library/Language/iCNF/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "iCNF is a data format and does not have a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/iCNF/run.sh b/@ether/library/Language/iCNF/run.sh new file mode 100755 index 00000000..1f7c816d --- /dev/null +++ b/@ether/library/Language/iCNF/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +cat "$1" diff --git a/@ether/library/Language/iProver/check.sh b/@ether/library/Language/iProver/check.sh new file mode 100755 index 00000000..ece29483 --- /dev/null +++ b/@ether/library/Language/iProver/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/gitlab.com/korovin/iprover" +command -v iprover >/dev/null 2>&1 || [[ -x "$REPO_DIR/iproveropt" ]] diff --git a/@ether/library/Language/iProver/install.sh b/@ether/library/Language/iProver/install.sh new file mode 100755 index 00000000..0574ba65 --- /dev/null +++ b/@ether/library/Language/iProver/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Installing iProver from source..." +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/gitlab.com/korovin/iprover" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://gitlab.com/korovin/iprover.git "$REPO_DIR" +fi +cd "$REPO_DIR" && ./configure && make +echo "iProver built in $REPO_DIR" diff --git a/@ether/library/Language/iProver/repl.sh b/@ether/library/Language/iProver/repl.sh new file mode 100755 index 00000000..4fc20239 --- /dev/null +++ b/@ether/library/Language/iProver/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "iProver does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/iProver/run.sh b/@ether/library/Language/iProver/run.sh new file mode 100755 index 00000000..3e07bdb1 --- /dev/null +++ b/@ether/library/Language/iProver/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/gitlab.com/korovin/iprover" +if command -v iprover >/dev/null 2>&1; then + exec iprover "$1" +else + exec "$REPO_DIR/iproveropt" "$1" +fi diff --git a/@ether/library/Language/min/check.sh b/@ether/library/Language/min/check.sh new file mode 100755 index 00000000..37e62c04 --- /dev/null +++ b/@ether/library/Language/min/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v min >/dev/null 2>&1 diff --git a/@ether/library/Language/min/install.sh b/@ether/library/Language/min/install.sh new file mode 100755 index 00000000..573b5c49 --- /dev/null +++ b/@ether/library/Language/min/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# min - https://h3rald.com/min/ +# https://github.com/h3rald/min +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/h3rald/min" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/h3rald/min.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v nim >/dev/null 2>&1 || { echo "Nim required. Install via: curl https://nim-lang.org/choosenim/init.sh -sSf | sh" >&2; exit 1; } +nimble build -y +sudo cp min /usr/local/bin/ 2>/dev/null || cp min "$HOME/.local/bin/" diff --git a/@ether/library/Language/min/repl.sh b/@ether/library/Language/min/repl.sh new file mode 100755 index 00000000..c2b9bf06 --- /dev/null +++ b/@ether/library/Language/min/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec min diff --git a/@ether/library/Language/min/run.sh b/@ether/library/Language/min/run.sh new file mode 100755 index 00000000..8d2cfb7e --- /dev/null +++ b/@ether/library/Language/min/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec min "$1" diff --git a/@ether/library/Language/newLISP/check.sh b/@ether/library/Language/newLISP/check.sh new file mode 100755 index 00000000..f075698e --- /dev/null +++ b/@ether/library/Language/newLISP/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v newlisp >/dev/null 2>&1 diff --git a/@ether/library/Language/newLISP/install.sh b/@ether/library/Language/newLISP/install.sh new file mode 100755 index 00000000..72d8d522 --- /dev/null +++ b/@ether/library/Language/newLISP/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing newLISP from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/kosh04/newlisp" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/kosh04/newlisp.git "$REPO_DIR" + fi + cd "$REPO_DIR" + make -j"$(nproc)" + sudo make install + exit 0 +fi +if [[ "$(uname)" == "Darwin" ]]; then + brew install newlisp +elif command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y newlisp +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y newlisp +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm newlisp +else + echo "Unsupported package manager. Use --from-source." >&2; exit 1 +fi diff --git a/@ether/library/Language/newLISP/repl.sh b/@ether/library/Language/newLISP/repl.sh new file mode 100755 index 00000000..f261b680 --- /dev/null +++ b/@ether/library/Language/newLISP/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec newlisp diff --git a/@ether/library/Language/newLISP/run.sh b/@ether/library/Language/newLISP/run.sh new file mode 100755 index 00000000..59b5d9d8 --- /dev/null +++ b/@ether/library/Language/newLISP/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec newlisp "$@" diff --git a/@ether/library/Language/pomegranate/check.sh b/@ether/library/Language/pomegranate/check.sh new file mode 100755 index 00000000..c608d4f6 --- /dev/null +++ b/@ether/library/Language/pomegranate/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +python3 -c "import pomegranate" >/dev/null 2>&1 diff --git a/@ether/library/Language/pomegranate/install.sh b/@ether/library/Language/pomegranate/install.sh new file mode 100755 index 00000000..42ba763b --- /dev/null +++ b/@ether/library/Language/pomegranate/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + echo "Installing pomegranate from source..." + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/jmschrei/pomegranate" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/jmschrei/pomegranate.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install . + exit 0 +fi +pip install pomegranate diff --git a/@ether/library/Language/pomegranate/repl.sh b/@ether/library/Language/pomegranate/repl.sh new file mode 100755 index 00000000..8068e2a6 --- /dev/null +++ b/@ether/library/Language/pomegranate/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 -c "import pomegranate; import code; code.interact(local={'pomegranate': pomegranate})" diff --git a/@ether/library/Language/pomegranate/run.sh b/@ether/library/Language/pomegranate/run.sh new file mode 100755 index 00000000..3cbbcc7e --- /dev/null +++ b/@ether/library/Language/pomegranate/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec python3 "$@" diff --git a/@ether/library/Language/reStructuredText/check.sh b/@ether/library/Language/reStructuredText/check.sh new file mode 100755 index 00000000..08ca8eaa --- /dev/null +++ b/@ether/library/Language/reStructuredText/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v rst2html >/dev/null 2>&1 || command -v rst2html.py >/dev/null 2>&1 || true diff --git a/@ether/library/Language/reStructuredText/install.sh b/@ether/library/Language/reStructuredText/install.sh new file mode 100755 index 00000000..8d398c72 --- /dev/null +++ b/@ether/library/Language/reStructuredText/install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +# reStructuredText is a markup format; install docutils for processing +pip install docutils diff --git a/@ether/library/Language/reStructuredText/repl.sh b/@ether/library/Language/reStructuredText/repl.sh new file mode 100755 index 00000000..892fd8af --- /dev/null +++ b/@ether/library/Language/reStructuredText/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "reStructuredText is a markup format and does not provide a REPL." >&2 +exit 1 diff --git a/@ether/library/Language/reStructuredText/run.sh b/@ether/library/Language/reStructuredText/run.sh new file mode 100755 index 00000000..5adb5350 --- /dev/null +++ b/@ether/library/Language/reStructuredText/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec cat "$1" diff --git a/@ether/library/Language/redtt/check.sh b/@ether/library/Language/redtt/check.sh new file mode 100755 index 00000000..b0e5de50 --- /dev/null +++ b/@ether/library/Language/redtt/check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v redtt >/dev/null 2>&1 || { + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/RedPRL/redtt" + [[ -x "$REPO_DIR/_build/default/src/bin/main.exe" ]] +} diff --git a/@ether/library/Language/redtt/install.sh b/@ether/library/Language/redtt/install.sh new file mode 100755 index 00000000..85b4ff7e --- /dev/null +++ b/@ether/library/Language/redtt/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/RedPRL/redtt" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/RedPRL/redtt.git "$REPO_DIR" +fi +cd "$REPO_DIR" +opam install . --deps-only -y +dune build diff --git a/@ether/library/Language/redtt/repl.sh b/@ether/library/Language/redtt/repl.sh new file mode 100755 index 00000000..ea0b5d70 --- /dev/null +++ b/@ether/library/Language/redtt/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "redtt does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/redtt/run.sh b/@ether/library/Language/redtt/run.sh new file mode 100755 index 00000000..4cbad4d7 --- /dev/null +++ b/@ether/library/Language/redtt/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +if command -v redtt >/dev/null 2>&1; then + exec redtt "$1" +else + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/RedPRL/redtt" + exec "$REPO_DIR/_build/default/src/bin/main.exe" "$1" +fi diff --git a/@ether/library/Language/seL4/check.sh b/@ether/library/Language/seL4/check.sh new file mode 100755 index 00000000..ac5bab7a --- /dev/null +++ b/@ether/library/Language/seL4/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/seL4/seL4" +[[ -d "$REPO_DIR" ]] diff --git a/@ether/library/Language/seL4/install.sh b/@ether/library/Language/seL4/install.sh new file mode 100755 index 00000000..ed3beefc --- /dev/null +++ b/@ether/library/Language/seL4/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail +# seL4 microkernel - https://sel4.systems/ +# Build from source (requires cross-compilation toolchain) +if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y build-essential cmake ninja-build python3 python3-pip \ + gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libxml2-utils device-tree-compiler + pip3 install sel4-deps +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gcc gcc-c++ cmake ninja-build python3 python3-pip libxml2 dtc + pip3 install sel4-deps +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm base-devel cmake ninja python python-pip aarch64-linux-gnu-gcc dtc libxml2 + pip3 install sel4-deps +elif [[ "$(uname)" == "Darwin" ]]; then + brew install cmake ninja dtc libxml2 python3 + pip3 install sel4-deps +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/seL4/seL4" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/seL4/seL4.git "$REPO_DIR" +fi +echo "seL4 source cloned to $REPO_DIR" +echo "Build with: cd $REPO_DIR && mkdir build && cd build && ../init-build.sh && ninja" diff --git a/@ether/library/Language/seL4/repl.sh b/@ether/library/Language/seL4/repl.sh new file mode 100755 index 00000000..a24bd4a7 --- /dev/null +++ b/@ether/library/Language/seL4/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "seL4 does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/seL4/run.sh b/@ether/library/Language/seL4/run.sh new file mode 100755 index 00000000..17d7017f --- /dev/null +++ b/@ether/library/Language/seL4/run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "seL4 is a microkernel; source files are compiled as part of a seL4 project." +echo "Use: https://docs.sel4.systems/Tutorials/" >&2 +cat "$@" diff --git a/@ether/library/Language/staq/check.sh b/@ether/library/Language/staq/check.sh new file mode 100755 index 00000000..d125e991 --- /dev/null +++ b/@ether/library/Language/staq/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +command -v staq >/dev/null 2>&1 diff --git a/@ether/library/Language/staq/install.sh b/@ether/library/Language/staq/install.sh new file mode 100755 index 00000000..9ca5f824 --- /dev/null +++ b/@ether/library/Language/staq/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +# staq: quantum compilation toolkit - https://github.com/softwareQinc/staq +if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update && sudo apt-get install -y build-essential cmake +elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y gcc gcc-c++ cmake +elif command -v pacman >/dev/null 2>&1; then + sudo pacman -S --noconfirm base-devel cmake +elif [[ "$(uname)" == "Darwin" ]]; then + brew install cmake +fi +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/softwareQinc/staq" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/softwareQinc/staq.git "$REPO_DIR" +fi +cd "$REPO_DIR" && cmake -B build && cmake --build build -j"$(nproc)" && sudo cmake --install build diff --git a/@ether/library/Language/staq/repl.sh b/@ether/library/Language/staq/repl.sh new file mode 100755 index 00000000..82cb7d11 --- /dev/null +++ b/@ether/library/Language/staq/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "staq does not have an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/staq/run.sh b/@ether/library/Language/staq/run.sh new file mode 100755 index 00000000..a1b49eb1 --- /dev/null +++ b/@ether/library/Language/staq/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec staq "$@" diff --git a/@ether/library/Language/textX/check.sh b/@ether/library/Language/textX/check.sh new file mode 100755 index 00000000..43536b5d --- /dev/null +++ b/@ether/library/Language/textX/check.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python3 -c "import textx" 2>/dev/null diff --git a/@ether/library/Language/textX/install.sh b/@ether/library/Language/textX/install.sh new file mode 100755 index 00000000..7c1cfba9 --- /dev/null +++ b/@ether/library/Language/textX/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# textX: Python DSL framework - https://textx.github.io/textX/ +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/textX/textX" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/textX/textX.git "$REPO_DIR" + fi + cd "$REPO_DIR" && pip install . + exit 0 +fi +pip install textX diff --git a/@ether/library/Language/textX/repl.sh b/@ether/library/Language/textX/repl.sh new file mode 100755 index 00000000..8063d6f8 --- /dev/null +++ b/@ether/library/Language/textX/repl.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec python3 -c "import textx; import code; code.interact(local=dict(globals(), **locals()))" diff --git a/@ether/library/Language/textX/run.sh b/@ether/library/Language/textX/run.sh new file mode 100755 index 00000000..96a12985 --- /dev/null +++ b/@ether/library/Language/textX/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec textx "$@" diff --git a/@ether/library/Language/veriT/check.sh b/@ether/library/Language/veriT/check.sh new file mode 100755 index 00000000..9bacbf2e --- /dev/null +++ b/@ether/library/Language/veriT/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v veriT >/dev/null 2>&1 diff --git a/@ether/library/Language/veriT/install.sh b/@ether/library/Language/veriT/install.sh new file mode 100755 index 00000000..b3348852 --- /dev/null +++ b/@ether/library/Language/veriT/install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +# veriT SMT solver - https://verit.loria.fr/ +# Must be built from source +curl -fsSL "https://verit.loria.fr/distrib/veriT-stable2016.tar.gz" -o /tmp/veriT.tar.gz +mkdir -p /tmp/veriT-build +tar -xzf /tmp/veriT.tar.gz -C /tmp/veriT-build --strip-components=1 +cd /tmp/veriT-build +autoconf && ./configure && make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" +mkdir -p "$HOME/.local/bin" +cp veriT "$HOME/.local/bin/" +rm -rf /tmp/veriT-build /tmp/veriT.tar.gz diff --git a/@ether/library/Language/veriT/repl.sh b/@ether/library/Language/veriT/repl.sh new file mode 100755 index 00000000..98bb4497 --- /dev/null +++ b/@ether/library/Language/veriT/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec veriT --interactive diff --git a/@ether/library/Language/veriT/run.sh b/@ether/library/Language/veriT/run.sh new file mode 100755 index 00000000..f0e4debd --- /dev/null +++ b/@ether/library/Language/veriT/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec veriT "$1" diff --git a/@ether/library/Language/yacctt/check.sh b/@ether/library/Language/yacctt/check.sh new file mode 100755 index 00000000..bd701bf4 --- /dev/null +++ b/@ether/library/Language/yacctt/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v yacctt >/dev/null 2>&1 diff --git a/@ether/library/Language/yacctt/install.sh b/@ether/library/Language/yacctt/install.sh new file mode 100755 index 00000000..e2f7aa1c --- /dev/null +++ b/@ether/library/Language/yacctt/install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# yacctt - Yet Another Cubical Type Theory +# https://github.com/mortberg/yacctt +REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/mortberg/yacctt" +if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true +else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/mortberg/yacctt.git "$REPO_DIR" +fi +cd "$REPO_DIR" +command -v stack >/dev/null 2>&1 || { echo "Haskell Stack required." >&2; exit 1; } +stack build +stack install diff --git a/@ether/library/Language/yacctt/repl.sh b/@ether/library/Language/yacctt/repl.sh new file mode 100755 index 00000000..c5ed4d90 --- /dev/null +++ b/@ether/library/Language/yacctt/repl.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "yacctt does not provide an interactive REPL." >&2 +exit 1 diff --git a/@ether/library/Language/yacctt/run.sh b/@ether/library/Language/yacctt/run.sh new file mode 100755 index 00000000..89dad1f6 --- /dev/null +++ b/@ether/library/Language/yacctt/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec yacctt "$1" diff --git a/@ether/library/Language/zxlive/check.sh b/@ether/library/Language/zxlive/check.sh new file mode 100755 index 00000000..57ae5ad3 --- /dev/null +++ b/@ether/library/Language/zxlive/check.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +command -v zxlive >/dev/null 2>&1 || python3 -c "import zxlive" 2>/dev/null diff --git a/@ether/library/Language/zxlive/install.sh b/@ether/library/Language/zxlive/install.sh new file mode 100755 index 00000000..8513d600 --- /dev/null +++ b/@ether/library/Language/zxlive/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +# zxlive - graphical ZX-calculus editor +# https://github.com/zxcalc/zxlive +if [[ "${FROM_SOURCE:-false}" == "true" ]]; then + REPO_DIR="${ETHER_EXTERNAL_DIR:-/tmp}/github.com/zxcalc/zxlive" + if [[ -d "$REPO_DIR/.git" ]]; then + GIT_TERMINAL_PROMPT=0 git -C "$REPO_DIR" pull || true + else + mkdir -p "$(dirname "$REPO_DIR")" + GIT_TERMINAL_PROMPT=0 git clone https://github.com/zxcalc/zxlive.git "$REPO_DIR" + fi + cd "$REPO_DIR" + pip install -e . + exit 0 +fi +pip install zxlive diff --git a/@ether/library/Language/zxlive/repl.sh b/@ether/library/Language/zxlive/repl.sh new file mode 100755 index 00000000..9fe18898 --- /dev/null +++ b/@ether/library/Language/zxlive/repl.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec zxlive diff --git a/@ether/library/Language/zxlive/run.sh b/@ether/library/Language/zxlive/run.sh new file mode 100755 index 00000000..4129f17e --- /dev/null +++ b/@ether/library/Language/zxlive/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec zxlive "$1" diff --git a/@ether/library/README.md b/@ether/library/README.md new file mode 100644 index 00000000..35e9a9a1 --- /dev/null +++ b/@ether/library/README.md @@ -0,0 +1,14 @@ +- Should be able to switch versions/implementations at will Language.Ray%VERSION autocompleted. +- If there isnt a REPL available it should compile and run +- Autocomplete should automatically update depending on the language's defs. +- Verify installers work, + support for archs + test on all the archs, and make sure that when the authors change the way of installing that we have a check for that every once in a while. +- Index should have a "This is incorrect, it's changed or is different for so and so arch", and adjust automatically or submit a change. +- Rewrite all the scripts to .ray files +- When an update is done, see if that changes any of the indexed comparisons +- Allow manual update of some specific entry +- GitHub might refer to subdirectory in monorepo, should still be able to clone + might need a git login, so create an account just for this. (Verse compiler for instance) +- For the index, deduplicate files which are the same across versions/similar; only the changes. +- Integrate GitHub code search and other results from other websites; if deemed useful +- Portable format for the Index +- Simple filters like does recursion or other things apply on top of each other to narrow down the search space +- Structurally search equivalences to certain program patterns \ No newline at end of file diff --git a/@ether/library/mirror/package-lock.json b/@ether/library/mirror/package-lock.json new file mode 100644 index 00000000..c24c024b --- /dev/null +++ b/@ether/library/mirror/package-lock.json @@ -0,0 +1,828 @@ +{ + "name": "@ether/mirror", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@ether/mirror", + "version": "0.1.0", + "devDependencies": { + "@types/node": "^18.0.0", + "tsx": "^4.21.0", + "typescript": "^5.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "18.19.130", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + } + }, + "dependencies": { + "@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "dev": true, + "optional": true + }, + "@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "dev": true, + "optional": true + }, + "@types/node": { + "version": "18.19.130", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + }, + "esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, + "tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "requires": { + "esbuild": "~0.27.0", + "fsevents": "~2.3.3", + "get-tsconfig": "^4.7.5" + } + }, + "typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + } + } +} diff --git a/@ether/library/mirror/package.json b/@ether/library/mirror/package.json new file mode 100644 index 00000000..174350cc --- /dev/null +++ b/@ether/library/mirror/package.json @@ -0,0 +1,15 @@ +{ + "name": "@ether/mirror", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "cli": "tsx src/cli.ts", + "build": "tsc --noEmit" + }, + "devDependencies": { + "@types/node": "^18.0.0", + "tsx": "^4.21.0", + "typescript": "^5.0.0" + } +} diff --git a/@ether/library/mirror/src/adapters/adapter.ts b/@ether/library/mirror/src/adapters/adapter.ts new file mode 100644 index 00000000..e8d3dc43 --- /dev/null +++ b/@ether/library/mirror/src/adapters/adapter.ts @@ -0,0 +1,105 @@ +import type { PlatformConfig, PackageEntry, RepoEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; + +/** + * Interface for package registry adapters (npm, PyPI, crates.io, etc.) + */ +export interface RegistryAdapter { + platform: PlatformConfig; + + /** + * Full enumeration: yield every package from the registry. + * Adapters should call indexer.checkpoint() periodically with their cursor. + * Resumes from indexer.getCursor() if non-null. + */ + enumerate(indexer: Indexer): AsyncGenerator; + + /** + * Incremental update: yield only packages changed since last sync. + * Uses indexer.getCursor() to determine where to start. + */ + enumerateIncremental(indexer: Indexer): AsyncGenerator; + + /** + * Fetch a single package's metadata. + */ + fetchPackage(indexer: Indexer, name: string, scope?: string): Promise; + + /** + * Download a specific version's tarball/archive. + */ + downloadVersion(indexer: Indexer, name: string, version: string, scope?: string): Promise; +} + +/** + * Interface for VCS platform adapters (GitHub, GitLab, Bitbucket). + */ +export interface VCSAdapter { + platform: PlatformConfig; + + /** + * Enumerate all repositories. Yields repo entries. + * Resumes from indexer.getCursor(). + */ + enumerate(indexer: Indexer): AsyncGenerator; + + /** + * Incremental update: yield repos created/updated since last sync. + */ + enumerateIncremental(indexer: Indexer): AsyncGenerator; + + /** + * Clone a single repo (git clone --bare) or update (git fetch) if exists. + * Also fetches releases. + */ + cloneRepo(indexer: Indexer, owner: string, repo: string): Promise; + + /** + * Fetch metadata only for a repo (no git clone). + */ + fetchRepo(indexer: Indexer, owner: string, repo: string): Promise; + + /** + * Fetch all releases/tags + download assets. + */ + fetchReleases(indexer: Indexer, owner: string, repo: string): Promise; + + /** + * Fetch a single release by tag. + */ + fetchRelease(indexer: Indexer, owner: string, repo: string, tag: string): Promise; +} + +/** + * Registry of all adapters, keyed by platform ID. + */ +const registryAdapters = new Map Promise>(); +const vcsAdapters = new Map Promise>(); + +export function registerRegistryAdapter(platformId: string, factory: () => Promise): void { + registryAdapters.set(platformId, factory); +} + +export function registerVCSAdapter(platformId: string, factory: () => Promise): void { + vcsAdapters.set(platformId, factory); +} + +export async function getRegistryAdapter(platformId: string): Promise { + const factory = registryAdapters.get(platformId); + if (!factory) return null; + return factory(); +} + +export async function getVCSAdapter(platformId: string): Promise { + const factory = vcsAdapters.get(platformId); + if (!factory) return null; + return factory(); +} + +export function allRegistryAdapterIds(): string[] { + return [...registryAdapters.keys()]; +} + +export function allVCSAdapterIds(): string[] { + return [...vcsAdapters.keys()]; +} diff --git a/@ether/library/mirror/src/adapters/bitbucket.ts b/@ether/library/mirror/src/adapters/bitbucket.ts new file mode 100644 index 00000000..1582922c --- /dev/null +++ b/@ether/library/mirror/src/adapters/bitbucket.ts @@ -0,0 +1,199 @@ +import type { PlatformConfig, RepoEntry, ReleaseEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { VCS_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson, httpGet } from '../core/http.js'; +import { repoPath } from '../core/shard.js'; +import { exists } from '../core/storage.js'; +import type { VCSAdapter } from './adapter.js'; +import { execSync } from 'node:child_process'; +import path from 'node:path'; + +export const platform = VCS_PLATFORMS['Bitbucket']; + +function authHeaders(): Record { + const user = process.env['BITBUCKET_USER']; + const pass = process.env['BITBUCKET_APP_PASSWORD']; + if (user && pass) { + return { Authorization: `Basic ${Buffer.from(`${user}:${pass}`).toString('base64')}` }; + } + return {}; +} + +export class BitbucketAdapter implements VCSAdapter { + platform: PlatformConfig = platform; + + async *enumerate(indexer: Indexer): AsyncGenerator { + // Bitbucket uses next URL pagination + let url: string | null = 'https://api.bitbucket.org/2.0/repositories?pagelen=100&fields=next,values.full_name,values.name,values.description,values.links.html.href,values.mainbranch.name,values.language,values.updated_on,values.owner.display_name'; + const cursor = indexer.getCursor(); + if (cursor !== null && typeof cursor === 'string' && cursor.startsWith('http')) { + url = cursor; + } + + let count = 0; + while (url) { + const data = await fetchJson>(url, { + headers: authHeaders(), + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + const values = data['values'] as Array> ?? []; + if (!values.length) break; + + for (const repo of values) { + const fullName = repo['full_name'] as string; + if (!fullName) continue; + const [owner, name] = fullName.split('/'); + if (!owner || !name) continue; + + const entry: RepoEntry = { + owner, + name, + fullName, + description: (repo['description'] as string) ?? undefined, + url: (repo['links'] as Record)?.['html'] as string ?? + ((repo['links'] as Record)?.['html'] as Record)?.['href'] as string ?? '', + defaultBranch: (repo['mainbranch'] as Record)?.['name'] as string ?? undefined, + language: (repo['language'] as string) ?? undefined, + updatedAt: (repo['updated_on'] as string) ?? undefined, + raw: repo, + }; + + await indexer.addRepo(entry, repo); + yield entry; + count++; + } + + const nextUrl = data['next'] as string | undefined; + if (nextUrl) { + url = nextUrl; + await indexer.checkpoint(nextUrl); + } else { + url = null; + } + + if (count % 1000 === 0) { + console.log(` ${count} Bitbucket repos enumerated...`); + } + } + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // Bitbucket uses next URL; incremental = resume from cursor + yield* this.enumerate(indexer); + } + + async cloneRepo(indexer: Indexer, owner: string, repo: string): Promise { + const dir = repoPath(indexer.dataRoot, this.platform.id, owner, repo); + const gitDir = path.join(dir, 'repo.git'); + const cloneUrl = `https://bitbucket.org/${owner}/${repo}.git`; + + if (await exists(gitDir)) { + console.log(` Updating bare clone ${owner}/${repo}...`); + execSync(`git -C "${gitDir}" fetch --all --prune`, { stdio: 'inherit' }); + } else { + console.log(` Bare cloning ${owner}/${repo}...`); + execSync(`git clone --bare "${cloneUrl}" "${gitDir}"`, { stdio: 'inherit' }); + } + + await this.fetchRepo(indexer, owner, repo); + } + + async fetchRepo(indexer: Indexer, owner: string, repo: string): Promise { + const url = `https://api.bitbucket.org/2.0/repositories/${owner}/${repo}`; + const raw = await fetchJson>(url, { + headers: authHeaders(), + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + const entry: RepoEntry = { + owner, + name: repo, + fullName: `${owner}/${repo}`, + description: (raw['description'] as string) ?? undefined, + url: ((raw['links'] as Record)?.['html'] as Record)?.['href'] as string ?? '', + defaultBranch: (raw['mainbranch'] as Record)?.['name'] as string ?? undefined, + language: (raw['language'] as string) ?? undefined, + updatedAt: (raw['updated_on'] as string) ?? undefined, + raw, + }; + + await indexer.addRepo(entry, raw); + return entry; + } + + async fetchReleases(indexer: Indexer, owner: string, repo: string): Promise { + // Bitbucket doesn't have "releases" like GitHub/GitLab, but has tags + downloads + // Fetch tags + let url: string | null = `https://api.bitbucket.org/2.0/repositories/${owner}/${repo}/refs/tags?pagelen=100`; + + while (url) { + const tagData: Record = await fetchJson>(url, { + headers: authHeaders(), + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + const values = tagData['values'] as Array> ?? []; + for (const tag of values) { + const tagName = tag['name'] as string; + if (!tagName) continue; + + const release: ReleaseEntry = { + tag: tagName, + name: tagName, + publishedAt: (tag['date'] as string) ?? (tag['target'] as Record)?.['date'] as string ?? undefined, + raw: tag, + }; + + await indexer.addRelease(owner, repo, release); + } + + url = tagData['next'] as string | null ?? null; + } + + // Fetch downloads (if any) + try { + let dlUrl: string | null = `https://api.bitbucket.org/2.0/repositories/${owner}/${repo}/downloads?pagelen=100`; + while (dlUrl) { + const dlData: Record = await fetchJson>(dlUrl, { + headers: authHeaders(), + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + const dlValues = dlData['values'] as Array> ?? []; + for (const dl of dlValues) { + const dlName = dl['name'] as string; + const link = ((dl['links'] as Record)?.['self'] as Record)?.['href'] as string; + if (dlName && link) { + try { + await indexer.downloadReleaseAsset(link, owner, repo, 'downloads', dlName); + } catch (err) { + console.error(` Failed to download ${dlName}: ${err instanceof Error ? err.message : err}`); + } + } + } + + dlUrl = dlData['next'] as string | null ?? null; + } + } catch { + // Downloads may not be enabled for this repo + } + } + + async fetchRelease(indexer: Indexer, owner: string, repo: string, tag: string): Promise { + const url = `https://api.bitbucket.org/2.0/repositories/${owner}/${repo}/refs/tags/${encodeURIComponent(tag)}`; + const raw = await fetchJson>(url, { + headers: authHeaders(), + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + const release: ReleaseEntry = { + tag, + name: tag, + publishedAt: (raw['date'] as string) ?? (raw['target'] as Record)?.['date'] as string ?? undefined, + raw, + }; + + await indexer.addRelease(owner, repo, release); + } +} diff --git a/@ether/library/mirror/src/adapters/clojars.ts b/@ether/library/mirror/src/adapters/clojars.ts new file mode 100644 index 00000000..8ff36fa4 --- /dev/null +++ b/@ether/library/mirror/src/adapters/clojars.ts @@ -0,0 +1,137 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * Clojars package registry adapter (Clojure). + * + * Uses the Clojars JSON API: + * - Paginated list: GET https://clojars.org/api/artifacts?page={n} + * Returns JSON array of artifact objects per page + * - Per-package: GET https://clojars.org/api/artifacts/{group}/{name} + * Returns JSON with version details + * - Download JAR: https://clojars.org/repo/{group-path}/{name}/{version}/{name}-{version}.jar + * + * ~30K packages. Paginated by page number. + */ + +const API_BASE = 'https://clojars.org'; + +interface ClojarsArtifact { + jar_name: string; + group_name: string; + description?: string; + homepage?: string; + version: string; + created?: string; + downloads?: number; +} + +interface ClojarsArtifactDetail { + jar_name: string; + group_name: string; + description?: string; + homepage?: string; + url?: string; + scm?: { url?: string; tag?: string }; + licenses?: string[]; + recent_versions?: { version: string; downloads?: number; created?: string }[]; + downloads?: number; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['clojars']; + +export class ClojarsAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['clojars']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + const cursor = indexer.getCursor(); + let page = typeof cursor === 'number' ? cursor : 1; + let count = 0; + + while (true) { + const url = `${API_BASE}/api/artifacts?page=${page}`; + let artifacts: ClojarsArtifact[]; + + try { + artifacts = await fetchJson(url, indexer.httpOpts); + } catch { + break; + } + + if (!artifacts || artifacts.length === 0) break; + + for (const artifact of artifacts) { + const name = artifact.group_name === artifact.jar_name + ? artifact.jar_name + : `${artifact.group_name}/${artifact.jar_name}`; + + const entry: PackageEntry = { + name: artifact.jar_name, + scope: artifact.group_name !== artifact.jar_name ? artifact.group_name : undefined, + version: artifact.version, + description: artifact.description, + homepage: artifact.homepage, + downloads: artifact.downloads, + updatedAt: artifact.created, + raw: artifact, + }; + + await indexer.addPackage(entry, artifact); + yield entry; + count++; + } + + await indexer.checkpoint(page); + page++; + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // Clojars has no dedicated change feed. Re-enumerate fully. + // Could be optimized by checking page 1 for recently updated artifacts, + // but for 30K this is manageable. + yield* this.enumerate(indexer); + } + + async fetchPackage(indexer: Indexer, name: string, scope?: string): Promise { + const group = scope || name; + const url = `${API_BASE}/api/artifacts/${encodeURIComponent(group)}/${encodeURIComponent(name)}`; + const data = await fetchJson(url, indexer.httpOpts); + + const versions = data.recent_versions?.map(v => v.version); + + const entry: PackageEntry = { + name: data.jar_name, + scope: data.group_name !== data.jar_name ? data.group_name : undefined, + versions, + version: versions?.[0], + description: data.description, + homepage: data.homepage || data.url, + repository: data.scm?.url, + license: data.licenses?.join(', '), + downloads: data.downloads, + raw: data, + }; + + await indexer.addPackage(entry, data); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string, scope?: string): Promise { + const group = scope || name; + // Maven-style group path: dots → slashes + const groupPath = group.replace(/\./g, '/'); + const filename = `${name}-${version}.jar`; + const downloadUrl = `${API_BASE}/repo/${groupPath}/${encodeURIComponent(name)}/${version}/${filename}`; + + await indexer.downloadVersion(downloadUrl, name, version, filename, scope); + } +} diff --git a/@ether/library/mirror/src/adapters/cocoapods.ts b/@ether/library/mirror/src/adapters/cocoapods.ts new file mode 100644 index 00000000..5190f50d --- /dev/null +++ b/@ether/library/mirror/src/adapters/cocoapods.ts @@ -0,0 +1,255 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson, httpGet } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * CocoaPods registry adapter (Swift/Objective-C pods). + * + * ~100K pods. Uses two data sources: + * 1. CDN: https://cdn.cocoapods.org/all_pods.txt for full pod listing + * 2. Trunk API: https://trunk.cocoapods.org/api/v1/pods/{name} for metadata + * + * CDN uses md5-based sharding for podspec files: + * Specs/{md5[0]}/{md5[1]}/{md5[2]}/{name}/{version}/{name}.podspec.json + * + * Pods don't have direct tarballs -- they reference source git repos. + * For downloadVersion we save the podspec JSON as version metadata. + */ + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['cocoapods']; + +const CDN_BASE = 'https://cdn.cocoapods.org'; +const TRUNK_API = 'https://trunk.cocoapods.org/api/v1'; +const CHECKPOINT_EVERY = 500; // checkpoint every N pods processed + +interface TrunkPodResponse { + name?: string; + versions?: Array<{ + name: string; // this is the version string + created_at?: string; + }>; + owners?: Array<{ name?: string; email?: string }>; +} + +interface CdnPodspec { + name?: string; + version?: string; + summary?: string; + description?: string; + homepage?: string; + license?: string | { type?: string }; + source?: { + git?: string; + http?: string; + tag?: string; + }; + authors?: Record | string; + platforms?: Record; +} + +/** + * Compute md5 hex of a string and return the first 3 characters + * as individual shard path components. + */ +async function md5Shard(name: string): Promise<{ s1: string; s2: string; s3: string }> { + const crypto = await import('node:crypto'); + const hash = crypto.createHash('md5').update(name).digest('hex'); + return { + s1: hash[0], + s2: hash[1], + s3: hash[2], + }; +} + +function toPackageEntry(name: string, trunk?: TrunkPodResponse, spec?: CdnPodspec): PackageEntry { + const versions = trunk?.versions?.map(v => v.name); + const latestVersion = versions?.[versions.length - 1]; + const license = spec?.license + ? typeof spec.license === 'string' ? spec.license : spec.license.type + : undefined; + + return { + name, + version: latestVersion, + versions, + description: spec?.summary ?? spec?.description, + homepage: spec?.homepage, + repository: spec?.source?.git, + license, + updatedAt: trunk?.versions?.[trunk.versions.length - 1]?.created_at, + raw: { trunk, spec }, + }; +} + +export class CocoaPodsAdapter implements RegistryAdapter { + platform = platform; + + /** + * Fetch the full list of pod names from CDN. + */ + private async fetchAllPodNames(indexer: Indexer): Promise { + const url = `${CDN_BASE}/all_pods.txt`; + console.log(' [cocoapods] Fetching all_pods.txt...'); + + const response = await httpGet(url, indexer.httpOpts); + if (response.status !== 200) { + throw new Error(`HTTP ${response.status} fetching all_pods.txt`); + } + + return response.body + .split('\n') + .map(line => line.trim()) + .filter(line => line.length > 0); + } + + /** + * Fetch pod metadata from the Trunk API. + */ + private async fetchTrunkMeta(indexer: Indexer, name: string): Promise { + try { + return await fetchJson( + `${TRUNK_API}/pods/${encodeURIComponent(name)}`, + indexer.httpOpts + ); + } catch { + return null; + } + } + + /** + * Fetch a podspec JSON from CDN using md5 shard path. + */ + private async fetchPodspec(indexer: Indexer, name: string, version: string): Promise { + const { s1, s2, s3 } = await md5Shard(name); + const url = `${CDN_BASE}/Specs/${s1}/${s2}/${s3}/${encodeURIComponent(name)}/${encodeURIComponent(version)}/${encodeURIComponent(name)}.podspec.json`; + + try { + return await fetchJson(url, indexer.httpOpts); + } catch { + return null; + } + } + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + const allPods = await this.fetchAllPodNames(indexer); + console.log(` [cocoapods] Found ${allPods.length} pods`); + + // Resume from cursor (index into sorted pod list) + const cursor = indexer.getCursor(); + let startIdx = typeof cursor === 'number' ? cursor : 0; + + for (let i = startIdx; i < allPods.length; i++) { + const podName = allPods[i]; + + // Fetch metadata from Trunk API + const trunk = await this.fetchTrunkMeta(indexer, podName); + + // Try to fetch the latest podspec from CDN for richer metadata + let spec: CdnPodspec | null = null; + const latestVersion = trunk?.versions?.[trunk.versions.length - 1]?.name; + if (latestVersion) { + spec = await this.fetchPodspec(indexer, podName, latestVersion); + } + + const entry = toPackageEntry(podName, trunk ?? undefined, spec ?? undefined); + await indexer.addPackage(entry, { trunk, spec }); + yield entry; + + if ((i + 1) % CHECKPOINT_EVERY === 0) { + console.log(` [cocoapods] Progress: ${i + 1}/${allPods.length}`); + await indexer.checkpoint(i + 1); + } + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // CocoaPods CDN provides deprecated_pods.txt and all_pods_versions_*.txt + // For incremental, we re-fetch the full pod list and compare with + // what we have. Alternatively, we could check the CDN changelog, + // but the simplest approach is to re-enumerate since the list fetch is fast. + // + // For large-scale incremental, compare all_pods.txt line count with + // our totalIndexed and only process new entries. + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + const allPods = await this.fetchAllPodNames(indexer); + const totalIndexed = indexer.getState().totalIndexed; + + if (allPods.length <= totalIndexed) { + console.log(' [cocoapods] No new pods detected'); + await indexer.finish(); + return; + } + + // Process pods from where we left off (assumes sorted/appended) + console.log(` [cocoapods] ${allPods.length - totalIndexed} potentially new pods`); + + for (let i = totalIndexed; i < allPods.length; i++) { + const podName = allPods[i]; + const trunk = await this.fetchTrunkMeta(indexer, podName); + + let spec: CdnPodspec | null = null; + const latestVersion = trunk?.versions?.[trunk.versions.length - 1]?.name; + if (latestVersion) { + spec = await this.fetchPodspec(indexer, podName, latestVersion); + } + + const entry = toPackageEntry(podName, trunk ?? undefined, spec ?? undefined); + await indexer.addPackage(entry, { trunk, spec }); + yield entry; + + if ((i + 1) % CHECKPOINT_EVERY === 0) { + await indexer.checkpoint(i + 1); + } + } + + await indexer.finish(); + } + + async fetchPackage(indexer: Indexer, name: string): Promise { + console.log(` [cocoapods] Fetching package ${name}...`); + + const trunk = await this.fetchTrunkMeta(indexer, name); + if (!trunk) { + throw new Error(`Pod "${name}" not found on Trunk API`); + } + + let spec: CdnPodspec | null = null; + const latestVersion = trunk.versions?.[trunk.versions.length - 1]?.name; + if (latestVersion) { + spec = await this.fetchPodspec(indexer, name, latestVersion); + } + + const entry = toPackageEntry(name, trunk, spec ?? undefined); + await indexer.addPackage(entry, { trunk, spec }); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string): Promise { + // CocoaPods doesn't serve direct tarballs -- pods reference source git repos. + // We save the podspec JSON as version metadata instead. + console.log(` [cocoapods] Saving podspec for ${name}@${version}...`); + + const spec = await this.fetchPodspec(indexer, name, version); + if (spec) { + await indexer.addVersion(name, version, spec); + } else { + // Fallback: fetch from Trunk API and save version info + const trunk = await this.fetchTrunkMeta(indexer, name); + const versionInfo = trunk?.versions?.find(v => v.name === version); + if (versionInfo) { + await indexer.addVersion(name, version, versionInfo); + } else { + throw new Error(`Version ${version} not found for pod "${name}"`); + } + } + } +} diff --git a/@ether/library/mirror/src/adapters/conda.ts b/@ether/library/mirror/src/adapters/conda.ts new file mode 100644 index 00000000..2c51aaf3 --- /dev/null +++ b/@ether/library/mirror/src/adapters/conda.ts @@ -0,0 +1,391 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * Conda package registry adapter (multi-channel). + * + * Conda organizes packages into channels and subdirectories: + * - Channels: conda-forge, main (defaults), bioconda, etc. + * - Subdirs: noarch (platform-independent), linux-64, osx-64, win-64, etc. + * + * Repodata endpoint (large JSON per channel/subdir): + * GET https://conda.anaconda.org/{channel}/{subdir}/repodata.json + * + * Response shape: + * { + * packages: { "name-version-build.tar.bz2": { name, version, depends, license, ... } }, + * packages.conda: { "name-version-build.conda": { name, version, depends, license, ... } } + * } + * + * Download: + * GET https://conda.anaconda.org/{channel}/{subdir}/{filename} + * + * Cursor format: "channelIndex:subdirIndex:lastPackageName" for resumption. + * + * conda-forge/noarch alone has ~30K+ unique packages. + * Full enumeration deduplicates by package name across all channels. + */ + +const BASE_URL = 'https://conda.anaconda.org'; + +/** Channels to enumerate, ordered by priority (conda-forge is largest). */ +const CHANNELS = ['conda-forge', 'main', 'bioconda'] as const; + +/** Subdirectories to enumerate (start small: platform-independent + linux). */ +const SUBDIRS = ['noarch', 'linux-64'] as const; + +/** A single package record inside repodata.json. */ +interface CondaRepodataPackage { + name: string; + version: string; + build: string; + build_number?: number; + depends?: string[]; + license?: string; + license_family?: string; + md5?: string; + sha256?: string; + size?: number; + subdir?: string; + timestamp?: number; + [key: string]: unknown; +} + +/** Top-level shape of repodata.json. */ +interface CondaRepodata { + info?: { subdir?: string }; + packages?: Record; + 'packages.conda'?: Record; +} + +/** Aggregated info for a unique package name (across all filenames/versions). */ +interface AggregatedPackage { + name: string; + versions: Set; + latestVersion: string; + latestTimestamp: number; + license: string | undefined; + depends: string[] | undefined; + channel: string; + subdir: string; + /** The filename of the latest version (for download). */ + latestFilename: string; +} + +/** + * Parse the cursor string into channel index, subdir index, and last package name. + * Format: "channelIdx:subdirIdx:lastPackageName" + */ +function parseCursor(cursor: string | number | null): { channelIdx: number; subdirIdx: number; lastPackage: string | null } { + if (cursor === null || cursor === undefined) { + return { channelIdx: 0, subdirIdx: 0, lastPackage: null }; + } + const str = String(cursor); + const parts = str.split(':'); + if (parts.length < 2) { + return { channelIdx: 0, subdirIdx: 0, lastPackage: null }; + } + return { + channelIdx: parseInt(parts[0], 10) || 0, + subdirIdx: parseInt(parts[1], 10) || 0, + lastPackage: parts.length >= 3 ? parts.slice(2).join(':') : null, + }; +} + +function encodeCursor(channelIdx: number, subdirIdx: number, lastPackage: string | null): string { + return `${channelIdx}:${subdirIdx}:${lastPackage ?? ''}`; +} + +/** + * Aggregate all filenames in a repodata response into a map of unique package names. + * Each package name maps to its set of versions and the latest version info. + */ +function aggregateRepodata(repodata: CondaRepodata, channel: string, subdir: string): Map { + const pkgMap = new Map(); + + const processEntries = (entries: Record | undefined, filename: (key: string) => string) => { + if (!entries) return; + for (const [key, pkg] of Object.entries(entries)) { + let agg = pkgMap.get(pkg.name); + if (!agg) { + agg = { + name: pkg.name, + versions: new Set(), + latestVersion: pkg.version, + latestTimestamp: pkg.timestamp ?? 0, + license: pkg.license, + depends: pkg.depends, + channel, + subdir, + latestFilename: filename(key), + }; + pkgMap.set(pkg.name, agg); + } + agg.versions.add(pkg.version); + + const ts = pkg.timestamp ?? 0; + if (ts > agg.latestTimestamp) { + agg.latestTimestamp = ts; + agg.latestVersion = pkg.version; + agg.license = pkg.license; + agg.depends = pkg.depends; + agg.latestFilename = filename(key); + } + } + }; + + processEntries(repodata.packages, (key) => key); + processEntries(repodata['packages.conda'], (key) => key); + + return pkgMap; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['conda']; + +export class CondaAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['conda']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + const cursor = parseCursor(indexer.getCursor()); + const seen = new Set(); + let count = 0; + + for (let ci = cursor.channelIdx; ci < CHANNELS.length; ci++) { + const channel = CHANNELS[ci]; + const startSubdir = ci === cursor.channelIdx ? cursor.subdirIdx : 0; + + for (let si = startSubdir; si < SUBDIRS.length; si++) { + const subdir = SUBDIRS[si]; + const skipUntil = (ci === cursor.channelIdx && si === cursor.subdirIdx) ? cursor.lastPackage : null; + + console.error(` [conda] Fetching repodata: ${channel}/${subdir} ...`); + + let repodata: CondaRepodata; + try { + repodata = await fetchJson( + `${BASE_URL}/${channel}/${subdir}/repodata.json`, + { ...indexer.httpOpts, timeout: 120_000 } + ); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(` [conda] Failed to fetch ${channel}/${subdir}: ${msg}, skipping.`); + continue; + } + + const aggregated = aggregateRepodata(repodata, channel, subdir); + const sortedNames = [...aggregated.keys()].sort(); + + let skipping = skipUntil !== null; + + for (const name of sortedNames) { + // Resume logic: skip packages until we pass the cursor position + if (skipping) { + if (name <= skipUntil!) continue; + skipping = false; + } + + // Global deduplication: a package seen in an earlier channel/subdir is skipped + if (seen.has(name)) continue; + seen.add(name); + + const agg = aggregated.get(name)!; + const versions = [...agg.versions].sort(); + + const entry: PackageEntry = { + name: agg.name, + scope: channel, + version: agg.latestVersion, + versions, + license: agg.license, + description: agg.depends ? `depends: ${agg.depends.join(', ')}` : undefined, + raw: { + channel, + subdir, + latestFilename: agg.latestFilename, + latestTimestamp: agg.latestTimestamp, + versionCount: versions.length, + }, + }; + + await indexer.addPackage(entry, entry.raw); + yield entry; + + count++; + if (count % 500 === 0) { + await indexer.checkpoint(encodeCursor(ci, si, name)); + } + } + + // Finished this channel/subdir pair + await indexer.checkpoint(encodeCursor(ci, si + 1, null)); + } + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // Conda repodata has no change feed or timestamps endpoint. + // Re-fetch all repodata and yield only packages whose latest version + // timestamp is newer than the last sync. + const lastSyncStr = indexer.getState().lastSync; + if (!lastSyncStr) { + // No previous sync — fall back to full enumeration + yield* this.enumerate(indexer); + return; + } + + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + const lastSyncMs = new Date(lastSyncStr).getTime(); + let count = 0; + + for (const channel of CHANNELS) { + for (const subdir of SUBDIRS) { + console.error(` [conda] Incremental: fetching ${channel}/${subdir} ...`); + + let repodata: CondaRepodata; + try { + repodata = await fetchJson( + `${BASE_URL}/${channel}/${subdir}/repodata.json`, + { ...indexer.httpOpts, timeout: 120_000 } + ); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(` [conda] Failed to fetch ${channel}/${subdir}: ${msg}, skipping.`); + continue; + } + + const aggregated = aggregateRepodata(repodata, channel, subdir); + + for (const [name, agg] of aggregated) { + // Only yield packages updated after last sync + // Conda timestamps are in milliseconds (some are in seconds — normalize) + const ts = agg.latestTimestamp > 1e12 ? agg.latestTimestamp : agg.latestTimestamp * 1000; + if (ts <= lastSyncMs) continue; + + const versions = [...agg.versions].sort(); + + const entry: PackageEntry = { + name: agg.name, + scope: channel, + version: agg.latestVersion, + versions, + license: agg.license, + description: agg.depends ? `depends: ${agg.depends.join(', ')}` : undefined, + raw: { + channel, + subdir, + latestFilename: agg.latestFilename, + latestTimestamp: agg.latestTimestamp, + versionCount: versions.length, + }, + }; + + await indexer.addPackage(entry, entry.raw); + yield entry; + count++; + } + } + } + + console.error(` [conda] Incremental: ${count} updated packages found.`); + await indexer.finish(); + } + + async fetchPackage(indexer: Indexer, name: string, scope?: string): Promise { + // Use channeldata.json (lightweight per-channel metadata) instead of repodata.json + // channeldata.json has: { packages: { "name": { description, license, home, version, ... } } } + const channels = scope ? [scope] : [...CHANNELS]; + + for (const channel of channels) { + let channeldata: { packages?: Record> }; + try { + channeldata = await fetchJson<{ packages?: Record> }>( + `${BASE_URL}/${channel}/channeldata.json`, + { ...indexer.httpOpts, timeout: 60_000 } + ); + } catch { + continue; + } + + const pkg = channeldata.packages?.[name]; + if (!pkg) continue; + + const version = pkg['version'] as string | undefined; + const entry: PackageEntry = { + name, + scope: channel, + version, + description: (pkg['description'] as string) ?? undefined, + homepage: (pkg['home'] as string) ?? undefined, + license: (pkg['license'] as string) ?? undefined, + raw: { channel, ...pkg }, + }; + + await indexer.addPackage(entry, { channel, ...pkg }); + return entry; + } + + throw new Error(`Conda package not found: ${name} (searched channels: ${channels.join(', ')})`); + } + + async downloadVersion(indexer: Indexer, name: string, version: string, scope?: string): Promise { + // scope = channel (defaults to searching all channels) + const channels = scope ? [scope] : [...CHANNELS]; + + for (const channel of channels) { + for (const subdir of SUBDIRS) { + let repodata: CondaRepodata; + try { + repodata = await fetchJson( + `${BASE_URL}/${channel}/${subdir}/repodata.json`, + { ...indexer.httpOpts, timeout: 120_000 } + ); + } catch { + continue; + } + + // Search through both .tar.bz2 and .conda package entries + const allEntries: [string, CondaRepodataPackage][] = [ + ...Object.entries(repodata.packages ?? {}), + ...Object.entries(repodata['packages.conda'] ?? {}), + ]; + + // Find the matching filename for this name + version + // Prefer .conda format over .tar.bz2 (smaller, faster) + let matchFilename: string | null = null; + let matchBz2: string | null = null; + + for (const [filename, pkg] of allEntries) { + if (pkg.name === name && pkg.version === version) { + if (filename.endsWith('.conda')) { + matchFilename = filename; + break; // Preferred format found + } else { + matchBz2 = filename; + } + } + } + + const targetFilename = matchFilename ?? matchBz2; + if (!targetFilename) continue; + + const downloadUrl = `${BASE_URL}/${channel}/${subdir}/${targetFilename}`; + await indexer.downloadVersion(downloadUrl, name, version, targetFilename, scope ?? channel); + return; + } + } + + throw new Error( + `Conda package version not found: ${name}==${version} (searched channels: ${channels.join(', ')}, subdirs: ${[...SUBDIRS].join(', ')})` + ); + } +} diff --git a/@ether/library/mirror/src/adapters/cpan.ts b/@ether/library/mirror/src/adapters/cpan.ts new file mode 100644 index 00000000..583f4f9d --- /dev/null +++ b/@ether/library/mirror/src/adapters/cpan.ts @@ -0,0 +1,180 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; +import { gunzipSync } from 'node:zlib'; + +/** + * CPAN (MetaCPAN) package registry adapter (Perl). + * + * Enumeration uses the 02packages.details.txt.gz index file: + * GET https://cpan.metacpan.org/modules/02packages.details.txt.gz + * This is a gzipped DCF-like file listing all modules → distribution mappings. + * + * Per-distribution metadata: + * GET https://fastapi.metacpan.org/v1/release/{distribution} + * + * Download tarball: + * GET https://cpan.metacpan.org/authors/id/{author_path}/{dist}-{version}.tar.gz + * + * ~40K distributions. + */ + +const API_BASE = 'https://fastapi.metacpan.org/v1'; +const DOWNLOAD_BASE = 'https://cpan.metacpan.org'; + +interface MetaCPANRelease { + name: string; + distribution: string; + version: string; + version_numified?: number; + author: string; + date?: string; + abstract?: string; + license?: string[]; + download_url?: string; + status?: string; + resources?: { + homepage?: string; + repository?: { url?: string; web?: string }; + }; + metadata?: unknown; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['cpan']; + +export class CpanAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['cpan']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + // Use 02packages.details.txt.gz — a reliable static index of all CPAN modules. + // This avoids the Elasticsearch scroll API which can return HTTP 500. + const indexUrl = `${DOWNLOAD_BASE}/modules/02packages.details.txt.gz`; + const res = await fetch(indexUrl, { + headers: { 'User-Agent': 'ether-mirror/0.1' }, + }); + if (!res.ok) throw new Error(`CPAN 02packages.details.txt.gz returned HTTP ${res.status}`); + + const compressed = Buffer.from(await res.arrayBuffer()); + const text = gunzipSync(compressed).toString('utf-8'); + + // Parse: skip header (everything before first blank line), then data lines. + // Format: "Module::Name version A/AU/AUTHOR/Dist-1.23.tar.gz" + const lines = text.split('\n'); + let headerDone = false; + + // Group by distribution path to deduplicate (many modules → one distribution) + const distMap = new Map(); + + for (const line of lines) { + if (!headerDone) { + if (line.trim() === '') headerDone = true; + continue; + } + + const parts = line.trim().split(/\s+/); + if (parts.length < 3) continue; + + const version = parts[1] === 'undef' ? undefined : parts[1]; + const distPath = parts[2]; + + if (!distMap.has(distPath)) { + distMap.set(distPath, { distPath, version }); + } + } + + const dists = [...distMap.values()]; + const cursor = indexer.getCursor(); + const startIdx = typeof cursor === 'number' ? cursor : 0; + let count = 0; + + for (let i = startIdx; i < dists.length; i++) { + const dist = dists[i]; + const filename = dist.distPath.split('/').pop() || ''; + const base = filename.replace(/\.(tar\.gz|tgz|zip|tar\.bz2)$/i, ''); + // Split "Dist-Name-1.23" into name + version + const vMatch = base.match(/^(.+?)[-.](\d[\d._]*\w*)$/); + const distName = vMatch ? vMatch[1] : base; + const version = vMatch ? vMatch[2] : dist.version; + + const entry: PackageEntry = { + name: distName, + version, + raw: { + distPath: dist.distPath, + downloadUrl: `${DOWNLOAD_BASE}/authors/id/${dist.distPath}`, + }, + }; + + await indexer.addPackage(entry, entry.raw); + yield entry; + + count++; + if (count % 1000 === 0) { + await indexer.checkpoint(startIdx + count); + } + } + + await indexer.checkpoint(startIdx + count); + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // 02packages is small (~12MB compressed) — just re-enumerate fully. + yield* this.enumerate(indexer); + } + + async fetchPackage(indexer: Indexer, name: string): Promise { + const url = `${API_BASE}/release/${encodeURIComponent(name)}`; + const data = await fetchJson(url, indexer.httpOpts); + + const entry = this.releaseToEntry(data); + await indexer.addPackage(entry, data); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string): Promise { + // Fetch the release to get the download URL and author + const url = `${API_BASE}/release/${encodeURIComponent(name)}`; + let data: MetaCPANRelease; + + try { + data = await fetchJson(url, indexer.httpOpts); + } catch { + // Try with versioned name: distribution-version + const versionedUrl = `${API_BASE}/release/${encodeURIComponent(`${name}-${version}`)}`; + data = await fetchJson(versionedUrl, indexer.httpOpts); + } + + if (data.download_url) { + const filename = data.download_url.split('/').pop() || `${name}-${version}.tar.gz`; + await indexer.downloadVersion(data.download_url, name, version, filename); + } else { + // Construct download URL from author path + // CPAN author paths: first letter / first two letters / full author + // e.g., JOHNDOE → J/JO/JOHNDOE + const author = data.author; + const authorPath = `${author[0]}/${author.slice(0, 2)}/${author}`; + const filename = `${data.name}.tar.gz`; + const downloadUrl = `${DOWNLOAD_BASE}/authors/id/${authorPath}/${filename}`; + await indexer.downloadVersion(downloadUrl, name, version, filename); + } + } + + private releaseToEntry(rel: MetaCPANRelease): PackageEntry { + return { + name: rel.distribution, + version: rel.version, + description: rel.abstract, + homepage: rel.resources?.homepage, + repository: rel.resources?.repository?.url || rel.resources?.repository?.web, + license: rel.license?.join(', '), + updatedAt: rel.date, + raw: rel, + }; + } +} diff --git a/@ether/library/mirror/src/adapters/cran.ts b/@ether/library/mirror/src/adapters/cran.ts new file mode 100644 index 00000000..5497b80c --- /dev/null +++ b/@ether/library/mirror/src/adapters/cran.ts @@ -0,0 +1,164 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { httpGet } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * CRAN package registry adapter (R). + * + * Uses the PACKAGES DCF file: + * GET https://cran.r-project.org/src/contrib/PACKAGES + * + * The PACKAGES file is a Debian Control File (DCF) format where entries + * are separated by blank lines. Each entry has fields like: + * Package: name + * Version: x.y.z + * Depends: ... + * License: ... + * Title: ... + * Description: ... + * NeedsCompilation: yes/no + * + * Download tarball: + * GET https://cran.r-project.org/src/contrib/{name}_{version}.tar.gz + * + * ~20K packages. No cursor-based pagination; PACKAGES file is re-parsed. + */ + +const BASE_URL = 'https://cran.r-project.org'; +const PACKAGES_URL = `${BASE_URL}/src/contrib/PACKAGES`; + +interface CranPackage { + Package: string; + Version: string; + Title?: string; + Description?: string; + License?: string; + Depends?: string; + Imports?: string; + Suggests?: string; + NeedsCompilation?: string; + [key: string]: string | undefined; +} + +/** + * Parse DCF (Debian Control File) format used by CRAN's PACKAGES file. + * Entries are separated by blank lines. Fields are Key: Value, with + * continuation lines starting with whitespace. + */ +function parseDCF(text: string): CranPackage[] { + const results: CranPackage[] = []; + const blocks = text.split(/\n\s*\n/); + + for (const block of blocks) { + const trimmed = block.trim(); + if (!trimmed) continue; + + const pkg: Record = {}; + let currentKey = ''; + + for (const line of trimmed.split('\n')) { + if (/^\s/.test(line) && currentKey) { + // Continuation line + pkg[currentKey] += ' ' + line.trim(); + } else { + const colonIdx = line.indexOf(':'); + if (colonIdx > 0) { + currentKey = line.slice(0, colonIdx).trim(); + pkg[currentKey] = line.slice(colonIdx + 1).trim(); + } + } + } + + if (pkg['Package']) { + results.push(pkg as CranPackage); + } + } + + return results; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['cran']; + +export class CranAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['cran']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + const res = await httpGet(PACKAGES_URL, indexer.httpOpts); + if (res.status !== 200) { + throw new Error(`CRAN PACKAGES returned HTTP ${res.status}`); + } + + const packages = parseDCF(res.body); + + const cursor = indexer.getCursor(); + const startIdx = typeof cursor === 'number' ? cursor : 0; + let count = startIdx; + + for (let i = startIdx; i < packages.length; i++) { + const pkg = packages[i]; + + const entry: PackageEntry = { + name: pkg.Package, + version: pkg.Version, + description: pkg.Title || pkg.Description, + license: pkg.License, + raw: pkg, + }; + + await indexer.addPackage(entry, pkg); + yield entry; + + count++; + if (count % 500 === 0) { + await indexer.checkpoint(count); + } + } + + await indexer.checkpoint(count); + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // CRAN has no change feed. Re-parse the full PACKAGES file. + yield* this.enumerate(indexer); + } + + async fetchPackage(indexer: Indexer, name: string): Promise { + // Fetch the full PACKAGES file and find the named package + const res = await httpGet(PACKAGES_URL, indexer.httpOpts); + if (res.status !== 200) { + throw new Error(`CRAN PACKAGES returned HTTP ${res.status}`); + } + + const packages = parseDCF(res.body); + const pkg = packages.find(p => p.Package === name); + + if (!pkg) { + throw new Error(`CRAN package not found: ${name}`); + } + + const entry: PackageEntry = { + name: pkg.Package, + version: pkg.Version, + description: pkg.Title || pkg.Description, + license: pkg.License, + homepage: `${BASE_URL}/web/packages/${encodeURIComponent(name)}/index.html`, + raw: pkg, + }; + + await indexer.addPackage(entry, pkg); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string): Promise { + const filename = `${name}_${version}.tar.gz`; + const downloadUrl = `${BASE_URL}/src/contrib/${filename}`; + + await indexer.downloadVersion(downloadUrl, name, version, filename); + } +} diff --git a/@ether/library/mirror/src/adapters/crates-io.ts b/@ether/library/mirror/src/adapters/crates-io.ts new file mode 100644 index 00000000..d30ca132 --- /dev/null +++ b/@ether/library/mirror/src/adapters/crates-io.ts @@ -0,0 +1,207 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * crates.io registry adapter (Rust crates). + * + * API docs: https://crates.io/policies#crawling + * + * ~150K crates. Paginated API with 100 per page, sorted alphabetically. + * Rate limited to 1 req/sec (enforced by platform config: 10 req / 10s). + * Tarballs served from static.crates.io. + * + * Also supports a full database dump at: + * https://static.crates.io/db-dump.tar.gz + * but we use the paginated API for incremental resumability. + */ + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['crates-io']; + +const API_BASE = 'https://crates.io/api/v1'; +const STATIC_BASE = 'https://static.crates.io'; +const PAGE_SIZE = 100; +const CHECKPOINT_EVERY = 10; // checkpoint every N pages + +interface CrateListResponse { + crates: CrateListItem[]; + meta: { + total: number; + next_page?: string; + }; +} + +interface CrateListItem { + id: string; + name: string; + description?: string; + homepage?: string; + repository?: string; + max_version?: string; + max_stable_version?: string; + downloads?: number; + recent_downloads?: number; + updated_at?: string; + created_at?: string; + exact_match?: boolean; +} + +interface CrateDetailResponse { + crate: CrateListItem; + versions: Array<{ + id: number; + crate: string; + num: string; // version number + dl_path: string; + created_at?: string; + updated_at?: string; + yanked: boolean; + license?: string; + crate_size?: number; + }>; +} + +function toPackageEntry(crate: CrateListItem, versions?: string[], license?: string): PackageEntry { + return { + name: crate.name, + version: crate.max_stable_version ?? crate.max_version, + versions, + description: crate.description, + homepage: crate.homepage, + repository: crate.repository, + license, + downloads: crate.downloads, + updatedAt: crate.updated_at, + raw: crate, + }; +} + +export class CratesIoAdapter implements RegistryAdapter { + platform = platform; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + // Use seek-based pagination via meta.next_page to avoid the page>200 limit. + // Cursor is the full next_page URL (or null for start). + const cursor = indexer.getCursor(); + let nextUrl: string | null = typeof cursor === 'string' && cursor.includes('crates') + ? cursor + : `${API_BASE}/crates?per_page=${PAGE_SIZE}&sort=alpha`; + + let pageNum = 0; + + while (nextUrl) { + pageNum++; + + let response: CrateListResponse; + try { + response = await fetchJson(nextUrl, indexer.httpOpts); + } catch (err) { + await indexer.setError(`Failed at page ${pageNum}: ${err instanceof Error ? err.message : String(err)}`); + throw err; + } + + if (!response.crates || response.crates.length === 0) break; + + for (const crate of response.crates) { + const entry = toPackageEntry(crate); + await indexer.addPackage(entry, crate); + yield entry; + } + + // Use the seek-based next_page URL from the API response + const np = response.meta?.next_page; + if (np) { + nextUrl = np.startsWith('http') ? np : `https://crates.io${np}`; + } else { + nextUrl = null; + } + + if (pageNum % CHECKPOINT_EVERY === 0 && nextUrl) { + await indexer.checkpoint(nextUrl); + } + + if (response.crates.length < PAGE_SIZE) break; + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // crates.io supports sorting by recent updates. + // Use seek-based pagination to avoid page>200 limit. + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + const lastSync = indexer.getState().lastSync; + let nextUrl: string | null = `${API_BASE}/crates?per_page=${PAGE_SIZE}&sort=recent-updates`; + let pageNum = 0; + + while (nextUrl) { + pageNum++; + + let response: CrateListResponse; + try { + response = await fetchJson(nextUrl, indexer.httpOpts); + } catch (err) { + await indexer.setError(`Incremental failed at page ${pageNum}: ${err instanceof Error ? err.message : String(err)}`); + throw err; + } + + if (!response.crates || response.crates.length === 0) break; + + let foundOld = false; + for (const crate of response.crates) { + if (lastSync && crate.updated_at && crate.updated_at < lastSync) { + foundOld = true; + break; + } + const entry = toPackageEntry(crate); + await indexer.addPackage(entry, crate); + yield entry; + } + + if (foundOld) break; + if (response.crates.length < PAGE_SIZE) break; + + const np = response.meta?.next_page; + if (np) { + nextUrl = np.startsWith('http') ? np : `https://crates.io${np}`; + } else { + nextUrl = null; + } + + await indexer.checkpoint(nextUrl ?? `done:${pageNum}`); + } + + await indexer.finish(); + } + + async fetchPackage(indexer: Indexer, name: string): Promise { + const url = `${API_BASE}/crates/${encodeURIComponent(name)}`; + console.log(` [crates-io] Fetching crate ${name}...`); + + const response = await fetchJson(url, indexer.httpOpts); + const versions = response.versions + .filter(v => !v.yanked) + .map(v => v.num); + const license = response.versions[0]?.license; + + const entry = toPackageEntry(response.crate, versions, license ?? undefined); + await indexer.addPackage(entry, response); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string): Promise { + // Crate tarballs are at: https://static.crates.io/crates/{name}/{name}-{version}.crate + const url = `${STATIC_BASE}/crates/${encodeURIComponent(name)}/${encodeURIComponent(name)}-${encodeURIComponent(version)}.crate`; + const filename = `${name}-${version}.crate`; + console.log(` [crates-io] Downloading ${name}@${version}...`); + + await indexer.downloadVersion(url, name, version, filename); + } +} diff --git a/@ether/library/mirror/src/adapters/github.ts b/@ether/library/mirror/src/adapters/github.ts new file mode 100644 index 00000000..b6162d02 --- /dev/null +++ b/@ether/library/mirror/src/adapters/github.ts @@ -0,0 +1,194 @@ +import type { PlatformConfig, RepoEntry, ReleaseEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { VCS_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson, httpGet } from '../core/http.js'; +import { repoPath } from '../core/shard.js'; +import { exists } from '../core/storage.js'; +import type { VCSAdapter } from './adapter.js'; +import { execSync } from 'node:child_process'; +import path from 'node:path'; + +export const platform = VCS_PLATFORMS['GitHub']; + +function authHeaders(): Record { + const token = process.env['GITHUB_TOKEN']; + if (token) return { Authorization: `Bearer ${token}` }; + return {}; +} + +export class GitHubAdapter implements VCSAdapter { + platform: PlatformConfig = platform; + + async *enumerate(indexer: Indexer): AsyncGenerator { + if (!process.env['GITHUB_TOKEN']) { + throw new Error('GitHub adapter requires GITHUB_TOKEN env var (rate limit is 60 req/hr without token). export GITHUB_TOKEN=ghp_...'); + } + + let since = 0; + const cursor = indexer.getCursor(); + if (cursor !== null) since = Number(cursor); + + while (true) { + const url = `https://api.github.com/repositories?since=${since}`; + const repos = await fetchJson>>(url, { + headers: { Accept: 'application/vnd.github.v3+json', ...authHeaders() }, + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + if (!repos.length) break; + + for (const repo of repos) { + const owner = (repo['owner'] as Record)?.['login'] as string; + const name = repo['name'] as string; + if (!owner || !name) continue; + + const entry: RepoEntry = { + owner, + name, + fullName: `${owner}/${name}`, + description: (repo['description'] as string) ?? undefined, + url: repo['html_url'] as string, + defaultBranch: (repo['default_branch'] as string) ?? undefined, + language: (repo['language'] as string) ?? undefined, + raw: repo, + }; + + await indexer.addRepo(entry, repo); + yield entry; + } + + since = repos[repos.length - 1]!['id'] as number; + await indexer.checkpoint(since); + } + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // GitHub /repositories only supports since=, so incremental = resume from cursor + yield* this.enumerate(indexer); + } + + async cloneRepo(indexer: Indexer, owner: string, repo: string): Promise { + const dir = repoPath(indexer.dataRoot, this.platform.id, owner, repo); + const gitDir = path.join(dir, 'repo.git'); + + const cloneUrl = `https://github.com/${owner}/${repo}.git`; + + if (await exists(gitDir)) { + console.log(` Updating bare clone ${owner}/${repo}...`); + execSync(`git -C "${gitDir}" fetch --all --prune`, { stdio: 'inherit' }); + } else { + console.log(` Bare cloning ${owner}/${repo}...`); + execSync(`git clone --bare "${cloneUrl}" "${gitDir}"`, { stdio: 'inherit' }); + } + + // Fetch and save repo metadata + await this.fetchRepo(indexer, owner, repo); + } + + async fetchRepo(indexer: Indexer, owner: string, repo: string): Promise { + const url = `https://api.github.com/repos/${owner}/${repo}`; + const raw = await fetchJson>(url, { + headers: { Accept: 'application/vnd.github.v3+json', ...authHeaders() }, + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + const entry: RepoEntry = { + owner, + name: repo, + fullName: `${owner}/${repo}`, + description: (raw['description'] as string) ?? undefined, + url: raw['html_url'] as string, + defaultBranch: (raw['default_branch'] as string) ?? undefined, + stars: raw['stargazers_count'] as number | undefined, + language: (raw['language'] as string) ?? undefined, + updatedAt: (raw['updated_at'] as string) ?? undefined, + raw, + }; + + await indexer.addRepo(entry, raw); + return entry; + } + + async fetchReleases(indexer: Indexer, owner: string, repo: string): Promise { + let page = 1; + while (true) { + const url = `https://api.github.com/repos/${owner}/${repo}/releases?page=${page}&per_page=100`; + const releases = await fetchJson>>(url, { + headers: { Accept: 'application/vnd.github.v3+json', ...authHeaders() }, + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + if (!releases.length) break; + + for (const rel of releases) { + const tag = rel['tag_name'] as string; + if (!tag) continue; + + const assets = (rel['assets'] as Array> ?? []).map(a => ({ + name: a['name'] as string, + url: a['browser_download_url'] as string, + size: a['size'] as number | undefined, + })); + + const release: ReleaseEntry = { + tag, + name: (rel['name'] as string) ?? undefined, + body: (rel['body'] as string) ?? undefined, + publishedAt: (rel['published_at'] as string) ?? undefined, + assets, + raw: rel, + }; + + await indexer.addRelease(owner, repo, release); + + // Download release assets + for (const asset of assets) { + if (asset.url && asset.name) { + try { + await indexer.downloadReleaseAsset(asset.url, owner, repo, tag, asset.name); + } catch (err) { + console.error(` Failed to download asset ${asset.name}: ${err instanceof Error ? err.message : err}`); + } + } + } + } + + page++; + } + } + + async fetchRelease(indexer: Indexer, owner: string, repo: string, tag: string): Promise { + const url = `https://api.github.com/repos/${owner}/${repo}/releases/tags/${tag}`; + const rel = await fetchJson>(url, { + headers: { Accept: 'application/vnd.github.v3+json', ...authHeaders() }, + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + const assets = (rel['assets'] as Array> ?? []).map(a => ({ + name: a['name'] as string, + url: a['browser_download_url'] as string, + size: a['size'] as number | undefined, + })); + + const release: ReleaseEntry = { + tag, + name: (rel['name'] as string) ?? undefined, + body: (rel['body'] as string) ?? undefined, + publishedAt: (rel['published_at'] as string) ?? undefined, + assets, + raw: rel, + }; + + await indexer.addRelease(owner, repo, release); + + for (const asset of assets) { + if (asset.url && asset.name) { + try { + await indexer.downloadReleaseAsset(asset.url, owner, repo, tag, asset.name); + } catch (err) { + console.error(` Failed to download asset ${asset.name}: ${err instanceof Error ? err.message : err}`); + } + } + } + } +} diff --git a/@ether/library/mirror/src/adapters/gitlab.ts b/@ether/library/mirror/src/adapters/gitlab.ts new file mode 100644 index 00000000..64ccff4e --- /dev/null +++ b/@ether/library/mirror/src/adapters/gitlab.ts @@ -0,0 +1,209 @@ +import type { PlatformConfig, RepoEntry, ReleaseEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { VCS_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson, httpGet } from '../core/http.js'; +import { repoPath } from '../core/shard.js'; +import { exists } from '../core/storage.js'; +import type { VCSAdapter } from './adapter.js'; +import { execSync } from 'node:child_process'; +import path from 'node:path'; + +export const platform = VCS_PLATFORMS['GitLab']; + +function authHeaders(): Record { + const token = process.env['GITLAB_TOKEN']; + if (token) return { 'PRIVATE-TOKEN': token }; + return {}; +} + +export class GitLabAdapter implements VCSAdapter { + platform: PlatformConfig = platform; + + async *enumerate(indexer: Indexer): AsyncGenerator { + let idAfter = 0; + const cursor = indexer.getCursor(); + if (cursor !== null) idAfter = Number(cursor); + + while (true) { + const url = `https://gitlab.com/api/v4/projects?per_page=100&order_by=id&sort=asc&id_after=${idAfter}`; + const projects = await fetchJson>>(url, { + headers: authHeaders(), + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + if (!projects.length) break; + + for (const proj of projects) { + const pathWithNs = proj['path_with_namespace'] as string; + if (!pathWithNs) continue; + const parts = pathWithNs.split('/'); + const owner = parts.slice(0, -1).join('/'); + const name = parts[parts.length - 1]!; + + const entry: RepoEntry = { + owner, + name, + fullName: pathWithNs, + description: (proj['description'] as string) ?? undefined, + url: proj['web_url'] as string, + defaultBranch: (proj['default_branch'] as string) ?? undefined, + stars: proj['star_count'] as number | undefined, + updatedAt: (proj['last_activity_at'] as string) ?? undefined, + raw: proj, + }; + + await indexer.addRepo(entry, proj); + yield entry; + } + + idAfter = projects[projects.length - 1]!['id'] as number; + await indexer.checkpoint(idAfter); + } + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // GitLab keyset pagination with id_after resumes naturally + yield* this.enumerate(indexer); + } + + async cloneRepo(indexer: Indexer, owner: string, repo: string): Promise { + const dir = repoPath(indexer.dataRoot, this.platform.id, owner, repo); + const gitDir = path.join(dir, 'repo.git'); + const cloneUrl = `https://gitlab.com/${owner}/${repo}.git`; + + if (await exists(gitDir)) { + console.log(` Updating bare clone ${owner}/${repo}...`); + execSync(`git -C "${gitDir}" fetch --all --prune`, { stdio: 'inherit' }); + } else { + console.log(` Bare cloning ${owner}/${repo}...`); + execSync(`git clone --bare "${cloneUrl}" "${gitDir}"`, { stdio: 'inherit' }); + } + + await this.fetchRepo(indexer, owner, repo); + } + + async fetchRepo(indexer: Indexer, owner: string, repo: string): Promise { + const encoded = encodeURIComponent(`${owner}/${repo}`); + const url = `https://gitlab.com/api/v4/projects/${encoded}`; + const raw = await fetchJson>(url, { + headers: authHeaders(), + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + const entry: RepoEntry = { + owner, + name: repo, + fullName: `${owner}/${repo}`, + description: (raw['description'] as string) ?? undefined, + url: raw['web_url'] as string, + defaultBranch: (raw['default_branch'] as string) ?? undefined, + stars: raw['star_count'] as number | undefined, + updatedAt: (raw['last_activity_at'] as string) ?? undefined, + raw, + }; + + await indexer.addRepo(entry, raw); + return entry; + } + + async fetchReleases(indexer: Indexer, owner: string, repo: string): Promise { + const encoded = encodeURIComponent(`${owner}/${repo}`); + let page = 1; + + while (true) { + const url = `https://gitlab.com/api/v4/projects/${encoded}/releases?page=${page}&per_page=100`; + const releases = await fetchJson>>(url, { + headers: authHeaders(), + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + if (!releases.length) break; + + for (const rel of releases) { + const tag = rel['tag_name'] as string; + if (!tag) continue; + + const links = (rel['assets'] as Record)?.['links'] as Array> ?? []; + const sources = (rel['assets'] as Record)?.['sources'] as Array> ?? []; + + const assets = [ + ...links.map(l => ({ + name: l['name'] as string, + url: l['direct_asset_url'] as string ?? l['url'] as string, + })), + ...sources.map(s => ({ + name: `source.${s['format'] as string}`, + url: s['url'] as string, + })), + ]; + + const release: ReleaseEntry = { + tag, + name: (rel['name'] as string) ?? undefined, + body: (rel['description'] as string) ?? undefined, + publishedAt: (rel['released_at'] as string) ?? undefined, + assets, + raw: rel, + }; + + await indexer.addRelease(owner, repo, release); + + for (const asset of assets) { + if (asset.url && asset.name) { + try { + await indexer.downloadReleaseAsset(asset.url, owner, repo, tag, asset.name); + } catch (err) { + console.error(` Failed to download ${asset.name}: ${err instanceof Error ? err.message : err}`); + } + } + } + } + + page++; + } + } + + async fetchRelease(indexer: Indexer, owner: string, repo: string, tag: string): Promise { + const encoded = encodeURIComponent(`${owner}/${repo}`); + const url = `https://gitlab.com/api/v4/projects/${encoded}/releases/${encodeURIComponent(tag)}`; + const rel = await fetchJson>(url, { + headers: authHeaders(), + rateLimiter: indexer.httpOpts.rateLimiter, + }); + + const links = (rel['assets'] as Record)?.['links'] as Array> ?? []; + const sources = (rel['assets'] as Record)?.['sources'] as Array> ?? []; + + const assets = [ + ...links.map(l => ({ + name: l['name'] as string, + url: l['direct_asset_url'] as string ?? l['url'] as string, + })), + ...sources.map(s => ({ + name: `source.${s['format'] as string}`, + url: s['url'] as string, + })), + ]; + + const release: ReleaseEntry = { + tag, + name: (rel['name'] as string) ?? undefined, + body: (rel['description'] as string) ?? undefined, + publishedAt: (rel['released_at'] as string) ?? undefined, + assets, + raw: rel, + }; + + await indexer.addRelease(owner, repo, release); + + for (const asset of assets) { + if (asset.url && asset.name) { + try { + await indexer.downloadReleaseAsset(asset.url, owner, repo, tag, asset.name); + } catch (err) { + console.error(` Failed to download ${asset.name}: ${err instanceof Error ? err.message : err}`); + } + } + } + } +} diff --git a/@ether/library/mirror/src/adapters/go.ts b/@ether/library/mirror/src/adapters/go.ts new file mode 100644 index 00000000..aef0c79f --- /dev/null +++ b/@ether/library/mirror/src/adapters/go.ts @@ -0,0 +1,169 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson, httpGet } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * Go Module Index adapter. + * + * API endpoints: + * - Module index: GET https://index.golang.org/index?since={timestamp} + * Returns JSON lines: {"Path":"...","Version":"...","Timestamp":"..."} + * Each batch returns up to 2000 entries. Paginate by using the last timestamp. + * - Version list: GET https://proxy.golang.org/{module}/@v/list + * - Version info: GET https://proxy.golang.org/{module}/@v/{version}.info + * - Download zip: GET https://proxy.golang.org/{module}/@v/{version}.zip + * + * ~1M modules. Excellent incremental support via timestamp cursor. + */ + +const INDEX_BASE = 'https://index.golang.org'; +const PROXY_BASE = 'https://proxy.golang.org'; + +/** Each line from the module index is a JSON object. */ +interface GoIndexEntry { + Path: string; + Version: string; + Timestamp: string; +} + +interface GoModuleInfo { + Version: string; + Time: string; +} + +function encodeModulePath(modulePath: string): string { + // Go module proxy uses case-encoded paths: uppercase letters become !lowercase + // e.g., "github.com/Azure/azure-sdk" → "github.com/!azure/azure-sdk" + return modulePath.replace(/[A-Z]/g, c => `!${c.toLowerCase()}`); +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['go']; + +export class GoAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['go']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + // Cursor is the last timestamp we processed + const cursor = indexer.getCursor(); + let since = typeof cursor === 'string' ? cursor : ''; + + let count = 0; + + while (true) { + const url = since + ? `${INDEX_BASE}/index?since=${encodeURIComponent(since)}` + : `${INDEX_BASE}/index`; + + const res = await httpGet(url, { + ...indexer.httpOpts, + timeout: 60_000, // index responses can be large + }); + if (res.status !== 200) { + throw new Error(`Go module index returned HTTP ${res.status}: ${res.body.slice(0, 200)}`); + } + + const lines = res.body.trim().split('\n').filter(l => l.length > 0); + if (lines.length === 0) break; + + let lastTimestamp = since; + + for (const line of lines) { + // Each line is a JSON object: {"Path":"...","Version":"...","Timestamp":"..."} + let parsed: GoIndexEntry; + try { + parsed = JSON.parse(line); + } catch { + continue; // skip malformed lines + } + + const modulePath = parsed.Path; + const version = parsed.Version; + const timestamp = parsed.Timestamp; + + if (!modulePath) continue; + + lastTimestamp = timestamp; + + const entry: PackageEntry = { + name: modulePath, + version, + updatedAt: timestamp, + raw: parsed, + }; + + await indexer.addPackage(entry, parsed); + yield entry; + count++; + } + + await indexer.checkpoint(lastTimestamp); + + // If we got fewer than 2000 entries, we've reached the end + if (lines.length < 2000) break; + + // Use last timestamp as cursor for next page + since = lastTimestamp; + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // The Go module index is inherently incremental — enumerate from the cursor + yield* this.enumerate(indexer); + } + + async fetchPackage(indexer: Indexer, name: string, _scope?: string): Promise { + const encoded = encodeModulePath(name); + + // Fetch version list + const listUrl = `${PROXY_BASE}/${encoded}/@v/list`; + const listRes = await httpGet(listUrl, indexer.httpOpts); + + if (listRes.status !== 200) { + throw new Error(`Go proxy returned HTTP ${listRes.status} for ${name}`); + } + + const versions = listRes.body.trim().split('\n').filter(v => v.length > 0); + const latestVersion = versions[versions.length - 1]; + + // Fetch info for the latest version + let updatedAt: string | undefined; + if (latestVersion) { + try { + const infoUrl = `${PROXY_BASE}/${encoded}/@v/${encodeURIComponent(latestVersion)}.info`; + const info = await fetchJson(infoUrl, indexer.httpOpts); + updatedAt = info.Time; + } catch { + // Info fetch is best-effort + } + } + + const entry: PackageEntry = { + name, + version: latestVersion, + versions, + updatedAt, + raw: { name, versions }, + }; + + await indexer.addPackage(entry, { name, versions }); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string, _scope?: string): Promise { + const encoded = encodeModulePath(name); + const downloadUrl = `${PROXY_BASE}/${encoded}/@v/${encodeURIComponent(version)}.zip`; + + // Use the last path segment as a short name, replace / with _ + const safeName = name.replace(/\//g, '_'); + const filename = `${safeName}-${version}.zip`; + + await indexer.downloadVersion(downloadUrl, name, version, filename); + } +} diff --git a/@ether/library/mirror/src/adapters/hackage.ts b/@ether/library/mirror/src/adapters/hackage.ts new file mode 100644 index 00000000..1da7ba55 --- /dev/null +++ b/@ether/library/mirror/src/adapters/hackage.ts @@ -0,0 +1,134 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson, httpGet } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * Hackage package registry adapter (Haskell). + * + * API endpoints: + * - Package list: GET https://hackage.haskell.org/packages/ (Accept: application/json) + * Returns JSON array of objects: { packageName: string } + * - Per-package: GET https://hackage.haskell.org/package/{name}.json + * Returns JSON with version info + * - Download: GET https://hackage.haskell.org/package/{name}-{version}/{name}-{version}.tar.gz + * + * ~18K packages. No cursor-based pagination; the full list is small enough + * for complete re-enumeration. + */ + +const BASE_URL = 'https://hackage.haskell.org'; + +interface HackagePackageListItem { + packageName: string; +} + +/** Hackage package JSON: keys are version strings, values are status/revision info. */ +type HackagePackageVersions = Record; + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['hackage']; + +export class HackageAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['hackage']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + // Fetch full package name list (Accept: application/json MUST come last to override) + const res = await httpGet(`${BASE_URL}/packages/`, { + ...indexer.httpOpts, + headers: { ...indexer.httpOpts.headers, Accept: 'application/json' }, + }); + + if (res.status !== 200) { + throw new Error(`Hackage package list returned HTTP ${res.status}: ${res.body.slice(0, 200)}`); + } + + let packages: HackagePackageListItem[]; + try { + packages = res.json(); + } catch { + throw new Error(`Hackage returned non-JSON response (${res.body.slice(0, 100)}...)`); + } + + if (!Array.isArray(packages) || packages.length === 0) { + throw new Error(`Hackage returned empty or invalid package list`); + } + + const cursor = indexer.getCursor(); + const startIdx = typeof cursor === 'number' ? cursor : 0; + let count = startIdx; + + for (let i = startIdx; i < packages.length; i++) { + const { packageName } = packages[i]; + + // Fetch version info per package (~18K packages, feasible) + let versions: string[] | undefined; + let latestVersion: string | undefined; + try { + const versionData = await fetchJson( + `${BASE_URL}/package/${encodeURIComponent(packageName)}.json`, + indexer.httpOpts, + ); + versions = Object.keys(versionData); + latestVersion = versions[versions.length - 1]; + } catch { + // Version fetch failed — continue with just the name + } + + const entry: PackageEntry = { + name: packageName, + version: latestVersion, + versions, + raw: packages[i], + }; + + await indexer.addPackage(entry, packages[i]); + yield entry; + + count++; + if (count % 500 === 0) { + await indexer.checkpoint(count); + } + } + + await indexer.checkpoint(count); + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // Hackage has no change feed. Re-enumerate the full list. + // For incremental, we just re-run full since 18K names is small. + yield* this.enumerate(indexer); + } + + async fetchPackage(indexer: Indexer, name: string): Promise { + const url = `${BASE_URL}/package/${encodeURIComponent(name)}.json`; + const data = await fetchJson(url, indexer.httpOpts); + + const versions = Object.keys(data); + const latestVersion = versions[versions.length - 1]; + + const entry: PackageEntry = { + name, + versions, + version: latestVersion, + raw: data, + }; + + await indexer.addPackage(entry, data); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string): Promise { + const filename = `${name}-${version}.tar.gz`; + const downloadUrl = `${BASE_URL}/package/${encodeURIComponent(name)}-${version}/${filename}`; + + await indexer.downloadVersion(downloadUrl, name, version, filename); + } +} diff --git a/@ether/library/mirror/src/adapters/hex.ts b/@ether/library/mirror/src/adapters/hex.ts new file mode 100644 index 00000000..97cbf988 --- /dev/null +++ b/@ether/library/mirror/src/adapters/hex.ts @@ -0,0 +1,180 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * Hex.pm registry adapter (Elixir/Erlang packages). + * + * API docs: https://github.com/hexpm/hexpm/blob/main/guides/api.md + * + * ~14K packages. Paginated API, 100 per page, sorted by name. + * Tarballs served from repo.hex.pm. + */ + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['hex']; + +const API_BASE = 'https://hex.pm/api'; +const REPO_BASE = 'https://repo.hex.pm'; +const PAGE_SIZE = 100; +const CHECKPOINT_EVERY = 5; // checkpoint every N pages + +interface HexPackageListItem { + name: string; + meta?: { + description?: string; + licenses?: string[]; + links?: Record; + }; + releases?: Array<{ version: string }>; + downloads?: { all?: number }; + updated_at?: string; + url?: string; +} + +interface HexPackageDetail { + name: string; + meta?: { + description?: string; + licenses?: string[]; + links?: Record; + }; + releases?: Array<{ + version: string; + url?: string; + inserted_at?: string; + }>; + downloads?: { all?: number }; + updated_at?: string; + url?: string; +} + +function toPackageEntry(pkg: HexPackageListItem | HexPackageDetail): PackageEntry { + const versions = pkg.releases?.map(r => r.version); + return { + name: pkg.name, + version: versions?.[0], // latest version (releases are ordered newest-first) + versions, + description: pkg.meta?.description, + license: pkg.meta?.licenses?.[0], + homepage: pkg.meta?.links?.['GitHub'] ?? pkg.meta?.links?.['Homepage'], + repository: pkg.meta?.links?.['GitHub'], + downloads: pkg.downloads?.all, + updatedAt: pkg.updated_at, + raw: pkg, + }; +} + +export class HexAdapter implements RegistryAdapter { + platform = platform; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + // Resume from cursor (page number) + const cursor = indexer.getCursor(); + let page = typeof cursor === 'number' ? cursor : 1; + + while (true) { + const url = `${API_BASE}/packages?page=${page}&per_page=${PAGE_SIZE}&sort=name`; + console.log(` [hex] Fetching page ${page}...`); + + let packages: HexPackageListItem[]; + try { + packages = await fetchJson(url, indexer.httpOpts); + } catch (err) { + await indexer.setError(`Failed at page ${page}: ${err instanceof Error ? err.message : String(err)}`); + throw err; + } + + if (!packages || packages.length === 0) { + break; // No more pages + } + + for (const pkg of packages) { + const entry = toPackageEntry(pkg); + await indexer.addPackage(entry, pkg); + yield entry; + } + + if (page % CHECKPOINT_EVERY === 0) { + await indexer.checkpoint(page); + } + + // If we got fewer than PAGE_SIZE results, this is the last page + if (packages.length < PAGE_SIZE) { + break; + } + + page++; + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // Hex doesn't have a dedicated incremental endpoint. + // We re-enumerate from page 1 sorted by updated_at desc and stop + // when we see packages older than our last sync. + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + const lastSync = indexer.getState().lastSync; + let page = 1; + + while (true) { + const url = `${API_BASE}/packages?page=${page}&per_page=${PAGE_SIZE}&sort=updated_at`; + console.log(` [hex] Incremental page ${page}...`); + + let packages: HexPackageListItem[]; + try { + packages = await fetchJson(url, indexer.httpOpts); + } catch (err) { + await indexer.setError(`Incremental failed at page ${page}: ${err instanceof Error ? err.message : String(err)}`); + throw err; + } + + if (!packages || packages.length === 0) break; + + let foundOld = false; + for (const pkg of packages) { + // If we have a lastSync and this package hasn't been updated since, stop + if (lastSync && pkg.updated_at && pkg.updated_at < lastSync) { + foundOld = true; + break; + } + const entry = toPackageEntry(pkg); + await indexer.addPackage(entry, pkg); + yield entry; + } + + if (foundOld) break; + if (packages.length < PAGE_SIZE) break; + + page++; + await indexer.checkpoint(page); + } + + await indexer.finish(); + } + + async fetchPackage(indexer: Indexer, name: string): Promise { + const url = `${API_BASE}/packages/${encodeURIComponent(name)}`; + console.log(` [hex] Fetching package ${name}...`); + + const pkg = await fetchJson(url, indexer.httpOpts); + const entry = toPackageEntry(pkg); + await indexer.addPackage(entry, pkg); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string): Promise { + const url = `${REPO_BASE}/tarballs/${encodeURIComponent(name)}-${encodeURIComponent(version)}.tar`; + const filename = `${name}-${version}.tar`; + console.log(` [hex] Downloading ${name}@${version}...`); + + await indexer.downloadVersion(url, name, version, filename); + } +} diff --git a/@ether/library/mirror/src/adapters/luarocks.ts b/@ether/library/mirror/src/adapters/luarocks.ts new file mode 100644 index 00000000..2aa4b841 --- /dev/null +++ b/@ether/library/mirror/src/adapters/luarocks.ts @@ -0,0 +1,197 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { httpGet } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * LuaRocks package registry adapter (Lua). + * + * LuaRocks has no JSON API. Data is sourced from the Lua manifest file: + * - Manifest: GET https://luarocks.org/manifest + * Returns a Lua table with `repository = { ["pkg"] = { ["ver"] = { ... } } }` + * - Download: https://luarocks.org/manifests/root/{name}-{version}.src.rock + * + * ~5K packages. The manifest is fetched once and parsed with regex. + */ + +const MANIFEST_URL = 'https://luarocks.org/manifest'; +const DOWNLOAD_BASE = 'https://luarocks.org/manifests/root'; + +/** + * Parsed package from the Lua manifest. + */ +interface ManifestPackage { + name: string; + versions: string[]; +} + +/** + * Parse the LuaRocks manifest (Lua table format) to extract package names and versions. + * + * The manifest looks like: + * repository = { + * ["15puzzle.nvim"] = { + * ["1.4.0-1"] = { + * { arch = "rockspec" }, { arch = "src" } + * }, + * ["1.3.0-1"] = { ... }, + * }, + * ["luasocket"] = { ... }, + * } + * + * We extract everything between `repository = {` and its closing `}`, + * then pull out top-level `["name"]` keys and their nested `["version"]` keys. + */ +function parseManifest(text: string): ManifestPackage[] { + // Find the repository block + const repoStart = text.indexOf('repository = {'); + if (repoStart === -1) return []; + + // We'll parse the block by tracking brace depth from the opening `{` + const startBrace = text.indexOf('{', repoStart); + if (startBrace === -1) return []; + + const packages: ManifestPackage[] = []; + + // Use regex to find top-level package entries and their version sub-keys. + // We scan line by line inside the repository block, tracking brace depth. + let depth = 0; + let currentPkg: string | null = null; + let currentVersions: string[] = []; + let pkgDepth = 0; + + // Pattern for a key like: ["package-name"] = { OR bare: package_name = { + const pkgKeyRe = /^\s*(?:\["([^"]+)"\]|([a-zA-Z_][a-zA-Z0-9_]*))\s*=\s*\{/; + // Pattern for closing brace (possibly with comma) + const closeBraceRe = /^\s*\}/; + + const lines = text.slice(startBrace).split('\n'); + + for (const line of lines) { + // Count braces on this line (outside of strings for simplicity; + // manifest keys don't contain braces so this is safe) + const openCount = (line.match(/\{/g) || []).length; + const closeCount = (line.match(/\}/g) || []).length; + + if (depth === 1 && currentPkg === null) { + // At top level of repository — look for package key + const pkgMatch = pkgKeyRe.exec(line); + if (pkgMatch) { + currentPkg = pkgMatch[1] ?? pkgMatch[2]; // quoted or bare name + currentVersions = []; + pkgDepth = depth; // depth before this line's braces + } + } else if (depth === 2 && currentPkg !== null) { + // Inside a package — look for version keys + const verMatch = pkgKeyRe.exec(line); + if (verMatch) { + currentVersions.push(verMatch[1] ?? verMatch[2]); + } + } + + depth += openCount - closeCount; + + // When we return to depth 1, the current package block has closed + if (currentPkg !== null && depth <= 1) { + packages.push({ name: currentPkg, versions: currentVersions }); + currentPkg = null; + currentVersions = []; + } + + // If depth drops to 0, we've exited the repository block + if (depth <= 0) break; + } + + return packages; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['luarocks']; + +export class LuaRocksAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['luarocks']; + + /** + * Cached parsed manifest (avoids re-fetching within a session). + */ + private manifestCache: ManifestPackage[] | null = null; + + private async getManifest(indexer: Indexer): Promise { + if (this.manifestCache) return this.manifestCache; + + const res = await httpGet(MANIFEST_URL, indexer.httpOpts); + if (res.status !== 200) { + throw new Error(`HTTP ${res.status} fetching LuaRocks manifest: ${res.body.slice(0, 200)}`); + } + + this.manifestCache = parseManifest(res.body); + return this.manifestCache; + } + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + const packages = await this.getManifest(indexer); + + const cursor = indexer.getCursor(); + const startIndex = typeof cursor === 'number' ? cursor : 0; + + for (let i = startIndex; i < packages.length; i++) { + const pkg = packages[i]; + const latestVersion = pkg.versions.length > 0 ? pkg.versions[0] : undefined; + + const entry: PackageEntry = { + name: pkg.name, + version: latestVersion, + versions: pkg.versions, + raw: { name: pkg.name, versions: pkg.versions }, + }; + + await indexer.addPackage(entry, { name: pkg.name, versions: pkg.versions }); + yield entry; + + // Checkpoint every 500 packages + if ((i + 1) % 500 === 0) { + await indexer.checkpoint(i + 1); + } + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // LuaRocks has no change feed — re-enumerate from scratch + // Clear manifest cache so we fetch a fresh copy + this.manifestCache = null; + yield* this.enumerate(indexer); + } + + async fetchPackage(indexer: Indexer, name: string, _scope?: string): Promise { + const packages = await this.getManifest(indexer); + + const pkg = packages.find(p => p.name === name); + if (!pkg) { + throw new Error(`Package "${name}" not found in LuaRocks manifest`); + } + + const latestVersion = pkg.versions.length > 0 ? pkg.versions[0] : undefined; + + const entry: PackageEntry = { + name: pkg.name, + version: latestVersion, + versions: pkg.versions, + raw: { name: pkg.name, versions: pkg.versions }, + }; + + await indexer.addPackage(entry, { name: pkg.name, versions: pkg.versions }); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string, _scope?: string): Promise { + const filename = `${name}-${version}.src.rock`; + const downloadUrl = `${DOWNLOAD_BASE}/${filename}`; + + await indexer.downloadVersion(downloadUrl, name, version, filename); + } +} diff --git a/@ether/library/mirror/src/adapters/maven.ts b/@ether/library/mirror/src/adapters/maven.ts new file mode 100644 index 00000000..f17389bb --- /dev/null +++ b/@ether/library/mirror/src/adapters/maven.ts @@ -0,0 +1,280 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * Maven Central registry adapter (Java / Kotlin / Scala). + * + * API endpoints: + * - Search (all artifacts): GET https://search.maven.org/solrsearch/select?q=*:*&rows=200&start={offset}&wt=json + * - Search (specific): GET https://search.maven.org/solrsearch/select?q=g:{groupId}+AND+a:{artifactId}&core=gav&rows=200&wt=json + * - Download JAR: GET https://repo1.maven.org/maven2/{groupPath}/{artifactId}/{version}/{artifactId}-{version}.jar + * Where groupPath = groupId with dots replaced by / + * + * ~10M artifacts. Rate limiting is important — Maven Central will block aggressive crawlers. + * Cursor: start offset for pagination. + */ + +const SEARCH_BASE = 'https://search.maven.org/solrsearch/select'; +const REPO_BASE = 'https://repo1.maven.org/maven2'; +const PAGE_SIZE = 200; + +interface SolrSearchResponse { + response: { + numFound: number; + start: number; + docs: SolrDoc[]; + }; +} + +interface SolrDoc { + id: string; // "groupId:artifactId:version" or "groupId:artifactId" + g: string; // groupId + a: string; // artifactId + v?: string; // version (latest for core search, specific for gav search) + latestVersion?: string; + p?: string; // packaging type (jar, pom, war, etc.) + timestamp?: number; // last modified timestamp in ms + ec?: string[]; // available file extensions + repositoryId?: string; + text?: string[]; + versionCount?: number; + tags?: string[]; +} + +interface SolrGavResponse { + response: { + numFound: number; + start: number; + docs: SolrGavDoc[]; + }; +} + +interface SolrGavDoc { + id: string; + g: string; + a: string; + v: string; + p?: string; + timestamp?: number; + ec?: string[]; + tags?: string[]; +} + +function groupIdToPath(groupId: string): string { + return groupId.replace(/\./g, '/'); +} + +/** + * Small delay to avoid hammering the search API. + */ +function delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['maven']; + +export class MavenAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['maven']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + const cursor = indexer.getCursor(); + let start = typeof cursor === 'number' ? cursor : 0; + + // First request to learn total count + const firstUrl = `${SEARCH_BASE}?q=*:*&rows=${PAGE_SIZE}&start=${start}&wt=json`; + const firstPage = await fetchJson(firstUrl, indexer.httpOpts); + const total = firstPage.response.numFound; + let count = 0; + + // Process the first page + for (const doc of firstPage.response.docs) { + const entry = this.docToEntry(doc); + await indexer.addPackage(entry, doc); + yield entry; + count++; + } + + start += firstPage.response.docs.length; + await indexer.checkpoint(start); + + // Continue paginating + while (start < total) { + // Be conservative with rate limiting + await delay(500); + + const url = `${SEARCH_BASE}?q=*:*&rows=${PAGE_SIZE}&start=${start}&wt=json`; + + let page: SolrSearchResponse; + try { + page = await fetchJson(url, indexer.httpOpts); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(` [maven] Error at offset ${start}: ${msg}`); + // Wait longer and retry once + await delay(5000); + page = await fetchJson(url, indexer.httpOpts); + } + + if (!page.response.docs || page.response.docs.length === 0) break; + + for (const doc of page.response.docs) { + const entry = this.docToEntry(doc); + await indexer.addPackage(entry, doc); + yield entry; + count++; + } + + start += page.response.docs.length; + await indexer.checkpoint(start); + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + const cursor = indexer.getCursor(); + if (cursor === null) { + yield* this.enumerate(indexer); + return; + } + + // Maven Central search API can sort by timestamp to find recently updated artifacts. + // We query for artifacts modified since our last sync using timestamp sort. + const lastOffset = typeof cursor === 'number' ? cursor : 0; + + // Use a timestamp-based query: sort by timestamp descending, fetch recent changes + // We'll paginate through all artifacts sorted by modification time + let start = 0; + const seen = new Set(); + + while (true) { + await delay(500); + + const url = `${SEARCH_BASE}?q=*:*&rows=${PAGE_SIZE}&start=${start}&sort=timestamp+desc&wt=json`; + let page: SolrSearchResponse; + + try { + page = await fetchJson(url, indexer.httpOpts); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(` [maven] Incremental error at offset ${start}: ${msg}`); + break; + } + + if (!page.response.docs || page.response.docs.length === 0) break; + + let allOld = true; + + for (const doc of page.response.docs) { + const key = `${doc.g}:${doc.a}`; + if (seen.has(key)) continue; + seen.add(key); + + const entry = this.docToEntry(doc); + await indexer.addPackage(entry, doc); + yield entry; + allOld = false; + } + + start += page.response.docs.length; + + // Stop after processing a reasonable number of recent changes + // or if the batch appears to have no new content + if (allOld || start >= 10000) break; + } + + // Keep the previous offset cursor so full enumeration can resume + await indexer.checkpoint(lastOffset); + await indexer.finish(); + } + + async fetchPackage(indexer: Indexer, name: string, scope?: string): Promise { + // name = artifactId, scope = groupId + const groupId = scope; + const artifactId = name; + + if (!groupId) { + // Search by artifactId alone + const url = `${SEARCH_BASE}?q=a:${encodeURIComponent(artifactId)}&rows=1&wt=json`; + const data = await fetchJson(url, indexer.httpOpts); + + if (!data.response.docs || data.response.docs.length === 0) { + throw new Error(`Maven artifact not found: ${artifactId}`); + } + + const doc = data.response.docs[0]; + const entry = this.docToEntry(doc); + await indexer.addPackage(entry, doc); + return entry; + } + + // Search by both groupId and artifactId, using GAV core for version listing + const url = `${SEARCH_BASE}?q=g:${encodeURIComponent(groupId)}+AND+a:${encodeURIComponent(artifactId)}&core=gav&rows=${PAGE_SIZE}&wt=json`; + const data = await fetchJson(url, indexer.httpOpts); + + if (!data.response.docs || data.response.docs.length === 0) { + throw new Error(`Maven artifact not found: ${groupId}:${artifactId}`); + } + + const versions = data.response.docs.map(d => d.v); + const latest = data.response.docs[0]; + + const entry: PackageEntry = { + name: artifactId, + scope: groupId, + version: latest.v, + versions, + updatedAt: latest.timestamp ? new Date(latest.timestamp).toISOString() : undefined, + raw: data.response.docs, + }; + + await indexer.addPackage(entry, data.response.docs); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string, scope?: string): Promise { + if (!scope) { + throw new Error(`Maven downloads require a groupId (scope). Use: downloadVersion(indexer, artifactId, version, groupId)`); + } + + const groupId = scope; + const artifactId = name; + const groupPath = groupIdToPath(groupId); + + // Try JAR first, fall back to POM + const jarFilename = `${artifactId}-${version}.jar`; + const jarUrl = `${REPO_BASE}/${groupPath}/${artifactId}/${version}/${jarFilename}`; + + try { + await indexer.downloadVersion(jarUrl, name, version, jarFilename, scope); + } catch { + // JAR might not exist (e.g., POM-only artifacts). Try POM. + const pomFilename = `${artifactId}-${version}.pom`; + const pomUrl = `${REPO_BASE}/${groupPath}/${artifactId}/${version}/${pomFilename}`; + await indexer.downloadVersion(pomUrl, name, version, pomFilename, scope); + } + } + + // -- internal -- + + private docToEntry(doc: SolrDoc): PackageEntry { + const latestVersion = doc.latestVersion || doc.v; + + return { + name: doc.a, + scope: doc.g, + version: latestVersion, + updatedAt: doc.timestamp ? new Date(doc.timestamp).toISOString() : undefined, + raw: doc, + }; + } +} diff --git a/@ether/library/mirror/src/adapters/nimble.ts b/@ether/library/mirror/src/adapters/nimble.ts new file mode 100644 index 00000000..130f791d --- /dev/null +++ b/@ether/library/mirror/src/adapters/nimble.ts @@ -0,0 +1,113 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * Nimble package registry adapter (Nim). + * + * Nimble's package list is a single JSON file hosted on GitHub: + * https://raw.githubusercontent.com/nim-lang/packages/master/packages.json + * + * The dataset is small (~2K packages), so full enumeration re-downloads + * the entire list each time. There is no cursor-based pagination. + */ + +const PACKAGES_URL = 'https://raw.githubusercontent.com/nim-lang/packages/master/packages.json'; + +interface NimblePackage { + name: string; + url: string; + method: string; + description?: string; + license?: string; + tags?: string[]; + web?: string; + alias?: string; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['nimble']; + +export class NimbleAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['nimble']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + const packages = await fetchJson(PACKAGES_URL, indexer.httpOpts); + + let count = 0; + for (const pkg of packages) { + // Skip aliases — they point to other packages + if (pkg.alias) continue; + + const entry: PackageEntry = { + name: pkg.name, + description: pkg.description, + homepage: pkg.web || pkg.url, + repository: pkg.url, + license: pkg.license, + raw: pkg, + }; + + await indexer.addPackage(entry, pkg); + yield entry; + + count++; + if (count % 200 === 0) { + await indexer.checkpoint(count); + } + } + + await indexer.checkpoint(count); + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // Small dataset — full re-enumeration is the incremental strategy + yield* this.enumerate(indexer); + } + + async fetchPackage(indexer: Indexer, name: string): Promise { + const packages = await fetchJson(PACKAGES_URL, indexer.httpOpts); + const pkg = packages.find(p => p.name.toLowerCase() === name.toLowerCase()); + + if (!pkg) { + throw new Error(`Nimble package not found: ${name}`); + } + + const entry: PackageEntry = { + name: pkg.name, + description: pkg.description, + homepage: pkg.web || pkg.url, + repository: pkg.url, + license: pkg.license, + raw: pkg, + }; + + await indexer.addPackage(entry, pkg); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string): Promise { + // Nimble packages are hosted in git repos — no tarball downloads. + // Save the metadata as the "download" artifact. + const packages = await fetchJson(PACKAGES_URL, indexer.httpOpts); + const pkg = packages.find(p => p.name.toLowerCase() === name.toLowerCase()); + + if (!pkg) { + throw new Error(`Nimble package not found: ${name}`); + } + + await indexer.addVersion(name, version, { + name: pkg.name, + version, + url: pkg.url, + method: pkg.method, + description: pkg.description, + license: pkg.license, + }); + } +} diff --git a/@ether/library/mirror/src/adapters/npm.ts b/@ether/library/mirror/src/adapters/npm.ts new file mode 100644 index 00000000..1fd5e8b5 --- /dev/null +++ b/@ether/library/mirror/src/adapters/npm.ts @@ -0,0 +1,241 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * npm package registry adapter (JavaScript / TypeScript). + * + * API endpoints: + * - CouchDB changes feed: GET https://replicate.npmjs.com/_changes?since={seq}&limit=1000&include_docs=true + * Returns { results: [{seq, id, doc, changes}], last_seq, pending } + * - Per-package (full): GET https://registry.npmjs.org/{name} + * - Per-package (version):GET https://registry.npmjs.org/{name}/{version} + * - Scoped package: GET https://registry.npmjs.org/@{scope}%2F{name} + * - Download tarball: GET https://registry.npmjs.org/{name}/-/{name}-{version}.tgz + * Scoped: GET https://registry.npmjs.org/@{scope}/{name}/-/{name}-{version}.tgz + * + * ~3M packages. The CouchDB changes feed is the canonical enumeration mechanism. + * Cursor: seq number from _changes feed. Perfect for incremental. + */ + +const CHANGES_URL = 'https://replicate.npmjs.com/_changes'; +const REGISTRY_URL = 'https://registry.npmjs.org'; +const CHANGES_LIMIT = 500; + +interface CouchDBChanges { + results: CouchDBChange[]; + last_seq: string | number; + pending?: number; +} + +interface CouchDBChange { + seq: string | number; + id: string; + changes: { rev: string }[]; + deleted?: boolean; + doc?: NpmPackageDoc; +} + +interface NpmPackageDoc { + _id: string; + _rev: string; + name: string; + description?: string; + 'dist-tags'?: Record; + versions?: Record; + time?: Record; + homepage?: string; + repository?: { type?: string; url?: string } | string; + license?: string | { type?: string }; + readme?: string; +} + +interface NpmVersionData { + name: string; + version: string; + description?: string; + homepage?: string; + license?: string | { type?: string }; + repository?: { type?: string; url?: string } | string; + dist?: { + tarball: string; + shasum?: string; + integrity?: string; + }; +} + +function parseScope(name: string): { scope?: string; shortName: string } { + if (name.startsWith('@')) { + const slashIdx = name.indexOf('/'); + if (slashIdx !== -1) { + return { + scope: name.substring(0, slashIdx), // "@angular" + shortName: name.substring(slashIdx + 1), // "core" + }; + } + } + return { shortName: name }; +} + +function extractLicense(license: string | { type?: string } | undefined): string | undefined { + if (!license) return undefined; + if (typeof license === 'string') return license; + return license.type; +} + +function extractRepoUrl(repo: { type?: string; url?: string } | string | undefined): string | undefined { + if (!repo) return undefined; + if (typeof repo === 'string') return repo; + return repo.url; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['npm']; + +export class NpmAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['npm']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + const cursor = indexer.getCursor(); + let since: string | number = cursor !== null ? cursor : 0; + let count = 0; + + while (true) { + // replicate.npmjs.com blocks include_docs=true, so we fetch IDs + // from the changes feed and then get each doc from the registry. + const url = `${CHANGES_URL}?since=${encodeURIComponent(String(since))}&limit=${CHANGES_LIMIT}`; + const data = await fetchJson(url, indexer.httpOpts); + + if (!data.results || data.results.length === 0) break; + + for (const change of data.results) { + if (change.id.startsWith('_design/')) continue; + if (change.deleted) continue; + + try { + const doc = await this.fetchDoc(change.id, indexer); + if (!doc || !doc.name) continue; + + const entry = this.docToEntry(doc); + await indexer.addPackage(entry, doc); + yield entry; + count++; + } catch { + // Package may have been deleted or is inaccessible — skip + continue; + } + } + + since = data.last_seq; + await indexer.checkpoint(since); + + if (data.pending !== undefined && data.pending === 0) break; + if (data.results.length < CHANGES_LIMIT) break; + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // The CouchDB changes feed is inherently incremental. + // enumerate() already resumes from cursor. + yield* this.enumerate(indexer); + } + + async fetchPackage(indexer: Indexer, name: string, scope?: string): Promise { + const fullName = scope ? `${scope}/${name}` : name; + const encodedName = fullName.startsWith('@') + ? fullName.replace('/', '%2F') + : encodeURIComponent(fullName); + + const url = `${REGISTRY_URL}/${encodedName}`; + const doc = await fetchJson(url, indexer.httpOpts); + + const entry = this.docToEntry(doc); + await indexer.addPackage(entry, doc); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string, scope?: string): Promise { + // Parse scope from name if not provided separately (e.g., "@angular/core" → scope="@angular", name="core") + let effectiveScope = scope; + let effectiveName = name; + if (!effectiveScope && name.startsWith('@')) { + const parsed = parseScope(name); + if (parsed.scope) { + effectiveScope = parsed.scope; + effectiveName = parsed.shortName; + } + } + + const fullName = effectiveScope ? `${effectiveScope}/${effectiveName}` : effectiveName; + + // Fetch the package document to get the exact tarball URL + const encodedName = fullName.startsWith('@') + ? fullName.replace('/', '%2F') + : encodeURIComponent(fullName); + + const url = `${REGISTRY_URL}/${encodedName}`; + const doc = await fetchJson(url, indexer.httpOpts); + + const versionData = doc.versions?.[version]; + if (!versionData) { + throw new Error(`Version ${version} not found for ${fullName}`); + } + + const tarballUrl = versionData.dist?.tarball; + if (!tarballUrl) { + const tgzName = `${effectiveName}-${version}.tgz`; + const prefix = effectiveScope ? `${effectiveScope}/${effectiveName}` : effectiveName; + const fallbackUrl = `${REGISTRY_URL}/${prefix}/-/${tgzName}`; + await indexer.downloadVersion(fallbackUrl, effectiveName, version, tgzName, effectiveScope || undefined); + return; + } + + const filename = `${effectiveName}-${version}.tgz`; + await indexer.downloadVersion(tarballUrl, effectiveName, version, filename, effectiveScope || undefined); + } + + // -- internal -- + + private async fetchDoc(name: string, indexer: Indexer): Promise { + const encodedName = name.startsWith('@') + ? name.replace('/', '%2F') + : encodeURIComponent(name); + return fetchJson(`${REGISTRY_URL}/${encodedName}`, indexer.httpOpts); + } + + private docToEntry(doc: NpmPackageDoc): PackageEntry { + const { scope, shortName } = parseScope(doc.name); + const distTags = doc['dist-tags'] || {}; + const latestVersion = distTags['latest']; + const versions = Object.keys(doc.versions || {}); + + // Get metadata from the latest version if available + const latestData = latestVersion ? doc.versions?.[latestVersion] : undefined; + + // Find the most recent update time + let updatedAt: string | undefined; + if (doc.time) { + const modified = doc.time['modified']; + if (modified) updatedAt = modified; + } + + return { + name: scope ? shortName : doc.name, + scope: scope || undefined, + version: latestVersion, + versions, + description: doc.description || latestData?.description, + homepage: doc.homepage || latestData?.homepage, + repository: extractRepoUrl(doc.repository || latestData?.repository), + license: extractLicense(doc.license || latestData?.license), + updatedAt, + raw: doc, + }; + } +} diff --git a/@ether/library/mirror/src/adapters/nuget.ts b/@ether/library/mirror/src/adapters/nuget.ts new file mode 100644 index 00000000..98184049 --- /dev/null +++ b/@ether/library/mirror/src/adapters/nuget.ts @@ -0,0 +1,294 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * NuGet package registry adapter (C# / F# / .NET). + * + * API endpoints (NuGet V3): + * - Service index: GET https://api.nuget.org/v3/index.json + * - Catalog index: GET https://api.nuget.org/v3/catalog0/index.json + * - Catalog page: GET {catalogPageUrl} + * - Registration: GET https://api.nuget.org/v3/registration5-gz-semver2/{id}/index.json + * - Download: GET https://api.nuget.org/v3-flatcontainer/{id}/{version}/{id}.{version}.nupkg + * + * ~400K packages. Uses the catalog for full/incremental enumeration. + */ + +const CATALOG_INDEX = 'https://api.nuget.org/v3/catalog0/index.json'; +const REGISTRATION_BASE = 'https://api.nuget.org/v3/registration5-gz-semver2'; +const FLAT_CONTAINER = 'https://api.nuget.org/v3-flatcontainer'; + +interface CatalogIndex { + commitTimeStamp: string; + count: number; + items: CatalogPage[]; +} + +interface CatalogPage { + '@id': string; + commitTimeStamp: string; + count: number; + items?: CatalogLeaf[]; +} + +interface CatalogLeaf { + '@id': string; + '@type': string; + commitTimeStamp: string; + 'nuget:id': string; + 'nuget:version': string; +} + +interface CatalogPageDetail { + '@id': string; + commitTimeStamp: string; + count: number; + items: CatalogLeaf[]; +} + +interface RegistrationIndex { + count: number; + items: RegistrationPage[]; +} + +interface RegistrationPage { + '@id': string; + count: number; + lower: string; + upper: string; + items?: RegistrationLeaf[]; +} + +interface RegistrationLeaf { + catalogEntry: { + '@id': string; + id: string; + version: string; + description?: string; + authors?: string; + licenseExpression?: string; + licenseUrl?: string; + projectUrl?: string; + listed?: boolean; + published?: string; + summary?: string; + tags?: string[]; + totalDownloads?: number; + }; + packageContent?: string; +} + +/** + * Cursor format: "pageIndex:commitTimeStamp" + * pageIndex = last fully processed catalog page index + * commitTimeStamp = for filtering within a page during incremental + */ +function parseCursor(cursor: string | number | null): { pageIndex: number; commitTime: string | null } { + if (cursor === null) return { pageIndex: 0, commitTime: null }; + const s = String(cursor); + const sep = s.indexOf(':'); + if (sep === -1) { + return { pageIndex: parseInt(s, 10) || 0, commitTime: null }; + } + return { + pageIndex: parseInt(s.substring(0, sep), 10) || 0, + commitTime: s.substring(sep + 1) || null, + }; +} + +function encodeCursor(pageIndex: number, commitTime: string): string { + return `${pageIndex}:${commitTime}`; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['nuget']; + +export class NuGetAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['nuget']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + const catalog = await fetchJson(CATALOG_INDEX, indexer.httpOpts); + const pages = catalog.items; + + // Sort pages by commitTimeStamp ascending + pages.sort((a, b) => a.commitTimeStamp.localeCompare(b.commitTimeStamp)); + + const { pageIndex: startPage } = parseCursor(indexer.getCursor()); + + // Track packages we've already yielded to deduplicate across pages + const seen = new Set(); + let count = 0; + + for (let i = startPage; i < pages.length; i++) { + const page = pages[i]; + let items = page.items; + + // If items aren't inlined, fetch the page + if (!items || items.length === 0) { + const pageDetail = await fetchJson(page['@id'], indexer.httpOpts); + items = pageDetail.items; + } + + for (const leaf of items) { + // Only process PackageDetails (not PackageDelete) + const leafType = leaf['@type']; + if (typeof leafType === 'string' && leafType.includes('PackageDelete')) continue; + + const id = leaf['nuget:id']; + const version = leaf['nuget:version']; + const lowerName = id.toLowerCase(); + + if (seen.has(lowerName)) continue; + seen.add(lowerName); + + const entry: PackageEntry = { + name: id, + version, + updatedAt: leaf.commitTimeStamp, + raw: leaf, + }; + + await indexer.addPackage(entry, leaf); + yield entry; + count++; + } + + await indexer.checkpoint(encodeCursor(i + 1, page.commitTimeStamp)); + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + const cursor = indexer.getCursor(); + const { pageIndex, commitTime } = parseCursor(cursor); + + if (!commitTime) { + // No previous timestamp — fall back to full + yield* this.enumerate(indexer); + return; + } + + const catalog = await fetchJson(CATALOG_INDEX, indexer.httpOpts); + const pages = catalog.items; + pages.sort((a, b) => a.commitTimeStamp.localeCompare(b.commitTimeStamp)); + + // Find pages with commitTimeStamp > our saved commitTime + const startIdx = pages.findIndex(p => p.commitTimeStamp > commitTime); + if (startIdx === -1) { + // Nothing new + await indexer.finish(); + return; + } + + const seen = new Set(); + let lastCommit = commitTime; + + for (let i = startIdx; i < pages.length; i++) { + const page = pages[i]; + let items = page.items; + + if (!items || items.length === 0) { + const pageDetail = await fetchJson(page['@id'], indexer.httpOpts); + items = pageDetail.items; + } + + for (const leaf of items) { + // Only items newer than our commit time + if (leaf.commitTimeStamp <= commitTime) continue; + + const leafType = leaf['@type']; + if (typeof leafType === 'string' && leafType.includes('PackageDelete')) continue; + + const id = leaf['nuget:id']; + const lowerName = id.toLowerCase(); + + if (seen.has(lowerName)) continue; + seen.add(lowerName); + + const entry: PackageEntry = { + name: id, + version: leaf['nuget:version'], + updatedAt: leaf.commitTimeStamp, + raw: leaf, + }; + + await indexer.addPackage(entry, leaf); + yield entry; + } + + lastCommit = page.commitTimeStamp; + await indexer.checkpoint(encodeCursor(i + 1, lastCommit)); + } + + await indexer.finish(); + } + + async fetchPackage(indexer: Indexer, name: string, _scope?: string): Promise { + const lowerId = name.toLowerCase(); + const url = `${REGISTRATION_BASE}/${lowerId}/index.json`; + const regIndex = await fetchJson(url, indexer.httpOpts); + + const allVersions: string[] = []; + let description: string | undefined; + let license: string | undefined; + let homepage: string | undefined; + let downloads: number | undefined; + let latestVersion: string | undefined; + + for (const page of regIndex.items) { + let leaves = page.items; + + // If items not inlined, fetch the page + if (!leaves || leaves.length === 0) { + const pageData = await fetchJson( + page['@id'], indexer.httpOpts + ); + leaves = pageData.items; + } + + for (const leaf of leaves) { + const ce = leaf.catalogEntry; + if (ce.listed === false) continue; + + allVersions.push(ce.version); + latestVersion = ce.version; + description = ce.description || description; + license = ce.licenseExpression || license; + homepage = ce.projectUrl || homepage; + if (ce.totalDownloads !== undefined) downloads = ce.totalDownloads; + } + } + + const entry: PackageEntry = { + name, + version: latestVersion, + versions: allVersions, + description, + homepage, + license, + downloads, + raw: regIndex, + }; + + await indexer.addPackage(entry, regIndex); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string, _scope?: string): Promise { + const lowerId = name.toLowerCase(); + const lowerVersion = version.toLowerCase(); + const downloadUrl = `${FLAT_CONTAINER}/${lowerId}/${lowerVersion}/${lowerId}.${lowerVersion}.nupkg`; + const filename = `${lowerId}.${lowerVersion}.nupkg`; + + await indexer.downloadVersion(downloadUrl, name, version, filename); + } +} diff --git a/@ether/library/mirror/src/adapters/opam.ts b/@ether/library/mirror/src/adapters/opam.ts new file mode 100644 index 00000000..d1ffe0de --- /dev/null +++ b/@ether/library/mirror/src/adapters/opam.ts @@ -0,0 +1,271 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson, httpGet } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * opam package registry adapter (OCaml). + * + * opam.ocaml.org has NO public REST/JSON API. Package data lives in the + * GitHub repository: https://github.com/ocaml/opam-repository + * + * Strategy: + * - enumerate(): Use GitHub Git Trees API to list all package directories + * under packages/. Two calls: one to get the root tree SHA, + * then one to get the packages/ subtree entries. + * - fetchPackage(): Use GitHub Contents API to list version directories for + * a package, then fetch each version's opam file from + * raw.githubusercontent.com. + * - downloadVersion(): Fetch the raw opam file for a specific version from + * raw.githubusercontent.com. + * + * ~4K+ packages. Unauthenticated GitHub API allows 60 req/hr; set GITHUB_TOKEN + * env var for 5000 req/hr. + */ + +const REPO_OWNER = 'ocaml'; +const REPO_NAME = 'opam-repository'; +const GITHUB_API = 'https://api.github.com'; +const GITHUB_RAW = 'https://raw.githubusercontent.com'; + +/** A single entry from the GitHub Git Trees API response. */ +interface GitTreeEntry { + path: string; + mode: string; + type: 'blob' | 'tree'; + sha: string; + size?: number; + url: string; +} + +/** GitHub Git Trees API response. */ +interface GitTreeResponse { + sha: string; + url: string; + tree: GitTreeEntry[]; + truncated: boolean; +} + +/** GitHub Contents API directory entry. */ +interface GithubContentsEntry { + name: string; + path: string; + sha: string; + type: 'file' | 'dir' | 'symlink' | 'submodule'; + url: string; +} + +/** + * Build GitHub API request headers, optionally including auth. + */ +function githubHeaders(): Record { + const headers: Record = { + Accept: 'application/vnd.github+json', + }; + const token = process.env['GITHUB_TOKEN']; + if (token) { + headers['Authorization'] = `Bearer ${token}`; + } + return headers; +} + +/** + * Simple parser for opam file fields. + * Extracts key fields from the opam file format. + */ +function parseOpamFile(content: string): Record { + const result: Record = {}; + + // Match simple string fields: key: "value" + const stringFieldRe = /^(\w[\w-]*):\s*"([^"]*)"\s*$/gm; + let m: RegExpExecArray | null; + while ((m = stringFieldRe.exec(content)) !== null) { + result[m[1]] = m[2]; + } + + // Match list fields: key: [ "val1" "val2" ] + const listFieldRe = /^(\w[\w-]*):\s*\[([^\]]*)\]/gm; + while ((m = listFieldRe.exec(content)) !== null) { + const items: string[] = []; + const itemRe = /"([^"]*)"/g; + let im: RegExpExecArray | null; + while ((im = itemRe.exec(m[2])) !== null) { + items.push(im[1]); + } + if (items.length > 0) { + result[m[1]] = items; + } + } + + return result; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['opam']; + +export class OpamAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['opam']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + if (!process.env['GITHUB_TOKEN']) { + throw new Error('opam adapter requires GITHUB_TOKEN env var (GitHub API rate limit is 60 req/hr without token). export GITHUB_TOKEN=ghp_...'); + } + + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + const ghHeaders = githubHeaders(); + const httpOpts = { + ...indexer.httpOpts, + headers: { ...ghHeaders, ...indexer.httpOpts.headers }, + }; + + // Step 1: Get the root tree SHA for the default branch (master) + const rootTree = await fetchJson( + `${GITHUB_API}/repos/${REPO_OWNER}/${REPO_NAME}/git/trees/master`, + httpOpts, + ); + + // Step 2: Find the "packages" directory entry in the root tree + const packagesEntry = rootTree.tree.find(e => e.path === 'packages' && e.type === 'tree'); + if (!packagesEntry) { + throw new Error('Could not find "packages" directory in opam-repository root tree'); + } + + // Step 3: Get the packages/ subtree — each child is a package name directory + const packagesTree = await fetchJson( + `${GITHUB_API}/repos/${REPO_OWNER}/${REPO_NAME}/git/trees/${packagesEntry.sha}`, + httpOpts, + ); + + // Sort by name for deterministic ordering + const packageDirs = packagesTree.tree + .filter(e => e.type === 'tree') + .sort((a, b) => a.path.localeCompare(b.path)); + + const cursor = indexer.getCursor(); + const startIdx = typeof cursor === 'number' ? cursor : 0; + let count = startIdx; + + for (let i = startIdx; i < packageDirs.length; i++) { + const dir = packageDirs[i]; + const name = dir.path; + + const entry: PackageEntry = { + name, + raw: { name, sha: dir.sha }, + }; + + await indexer.addPackage(entry, { name, sha: dir.sha }); + yield entry; + + count++; + if (count % 200 === 0) { + await indexer.checkpoint(count); + } + } + + await indexer.checkpoint(count); + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // opam-repository is small enough for full re-enumeration + yield* this.enumerate(indexer); + } + + async fetchPackage(indexer: Indexer, name: string): Promise { + const ghHeaders = githubHeaders(); + const httpOpts = { + ...indexer.httpOpts, + headers: { ...ghHeaders, ...indexer.httpOpts.headers }, + }; + + // List version directories: packages/{name}/ contains dirs like {name}.{version} + const contents = await fetchJson( + `${GITHUB_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/packages/${encodeURIComponent(name)}`, + httpOpts, + ); + + const versionDirs = contents + .filter(e => e.type === 'dir') + .map(e => e.name); + + // Extract version strings from directory names: "{name}.{version}" → "{version}" + const prefix = `${name}.`; + const versions = versionDirs + .filter(d => d.startsWith(prefix)) + .map(d => d.slice(prefix.length)) + .sort(); + + const latestVersion = versions[versions.length - 1]; + + // Fetch the opam file for the latest version to get metadata + let description: string | undefined; + let homepage: string | undefined; + let repository: string | undefined; + let license: string | undefined; + + if (latestVersion) { + const opamUrl = `${GITHUB_RAW}/${REPO_OWNER}/${REPO_NAME}/master/packages/${name}/${name}.${latestVersion}/opam`; + const opamRes = await httpGet(opamUrl, httpOpts); + if (opamRes.status === 200) { + const parsed = parseOpamFile(opamRes.body); + description = (typeof parsed['synopsis'] === 'string' ? parsed['synopsis'] : undefined) + || (typeof parsed['description'] === 'string' ? parsed['description'] : undefined); + const homepageVal = parsed['homepage']; + homepage = Array.isArray(homepageVal) ? homepageVal[0] : (typeof homepageVal === 'string' ? homepageVal : undefined); + const devRepo = parsed['dev-repo']; + repository = typeof devRepo === 'string' ? devRepo : undefined; + const licenseVal = parsed['license']; + license = typeof licenseVal === 'string' ? licenseVal : (Array.isArray(licenseVal) ? licenseVal[0] : undefined); + } + } + + const entry: PackageEntry = { + name, + versions, + version: latestVersion, + description, + homepage, + repository, + license, + raw: { name, versions, versionDirs }, + }; + + await indexer.addPackage(entry, { name, versions, versionDirs }); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string): Promise { + const ghHeaders = githubHeaders(); + const httpOpts = { + ...indexer.httpOpts, + headers: { ...ghHeaders, ...indexer.httpOpts.headers }, + }; + + // Fetch the opam file for this specific version + const opamUrl = `${GITHUB_RAW}/${REPO_OWNER}/${REPO_NAME}/master/packages/${name}/${name}.${version}/opam`; + const opamRes = await httpGet(opamUrl, httpOpts); + + if (opamRes.status !== 200) { + throw new Error(`Failed to fetch opam file for ${name}.${version}: HTTP ${opamRes.status}`); + } + + const parsed = parseOpamFile(opamRes.body); + + await indexer.addVersion(name, version, { + name, + version, + opamFileContent: opamRes.body, + synopsis: parsed['synopsis'], + description: parsed['description'], + license: parsed['license'], + homepage: parsed['homepage'], + authors: parsed['authors'], + maintainer: parsed['maintainer'], + depends: parsed['depends'], + 'dev-repo': parsed['dev-repo'], + }); + } +} diff --git a/@ether/library/mirror/src/adapters/packagist.ts b/@ether/library/mirror/src/adapters/packagist.ts new file mode 100644 index 00000000..86e23182 --- /dev/null +++ b/@ether/library/mirror/src/adapters/packagist.ts @@ -0,0 +1,226 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * Packagist package registry adapter (PHP / Composer). + * + * API endpoints: + * - Full list: GET https://packagist.org/packages/list.json + * - Per-package: GET https://packagist.org/packages/{vendor}/{name}.json + * - Incremental: GET https://packagist.org/metadata/changes.json?since={timestamp} + * + * ~400K packages. Package names are in "vendor/name" format. + */ + +const BASE = 'https://packagist.org'; + +interface PackagistList { + packageNames: string[]; +} + +interface PackagistChanges { + actions: PackagistChangeAction[]; + timestamp: number; +} + +interface PackagistChangeAction { + type: 'update' | 'delete' | 'resync' | 'new'; + package: string; + time: string; +} + +interface PackagistPackageResponse { + package: PackagistPackageData; +} + +interface PackagistPackageData { + name: string; + description?: string; + time?: string; + maintainers?: { name: string; avatar_url: string }[]; + versions: Record; + type?: string; + repository?: string; + github_stars?: number; + github_forks?: number; + downloads?: { total: number; monthly: number; daily: number }; + fapiVersion?: number; + language?: string; +} + +interface PackagistVersionData { + name: string; + description?: string; + version: string; + version_normalized: string; + license?: string[]; + homepage?: string; + time?: string; + dist?: { + url: string; + type: string; + shasum: string; + reference?: string; + }; + source?: { + url: string; + type: string; + reference?: string; + }; + require?: Record; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['packagist']; + +export class PackagistAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['packagist']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + // Get the full package name list + const list = await fetchJson(`${BASE}/packages/list.json`, indexer.httpOpts); + const names = list.packageNames; + + // Resume from cursor if available (index into the names array) + const cursor = indexer.getCursor(); + let startIdx = typeof cursor === 'number' ? cursor : 0; + + for (let i = startIdx; i < names.length; i++) { + const fullName = names[i]; // "vendor/package" + + try { + const entry = await this.fetchSinglePackage(indexer, fullName); + yield entry; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(` [packagist] Error fetching ${fullName}: ${msg}`); + } + + if ((i + 1) % 100 === 0) { + await indexer.checkpoint(i + 1); + } + } + + await indexer.checkpoint(names.length); + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + const cursor = indexer.getCursor(); + // Cursor is a UNIX timestamp (seconds) for the changes feed + const since = typeof cursor === 'number' ? cursor : 0; + + if (since === 0) { + // No previous cursor — fall back to full enumeration + yield* this.enumerate(indexer); + return; + } + + const url = `${BASE}/metadata/changes.json?since=${since}`; + const changes = await fetchJson(url, indexer.httpOpts); + + const seen = new Set(); + let count = 0; + + for (const action of changes.actions) { + if (action.type === 'delete') continue; + if (seen.has(action.package)) continue; + seen.add(action.package); + + try { + const entry = await this.fetchSinglePackage(indexer, action.package); + yield entry; + count++; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(` [packagist] Error fetching ${action.package}: ${msg}`); + } + + if (count % 50 === 0) { + await indexer.checkpoint(changes.timestamp); + } + } + + await indexer.checkpoint(changes.timestamp); + await indexer.finish(); + } + + async fetchPackage(indexer: Indexer, name: string, scope?: string): Promise { + // For Packagist, "scope" is the vendor prefix. Build "vendor/name" if scope provided. + const fullName = scope ? `${scope}/${name}` : name; + return this.fetchSinglePackage(indexer, fullName); + } + + async downloadVersion(indexer: Indexer, name: string, version: string, scope?: string): Promise { + const fullName = scope ? `${scope}/${name}` : name; + + // Split vendor/name consistently with fetchSinglePackage + const parts = fullName.split('/'); + const vendor = parts.length > 1 ? parts[0] : undefined; + const shortName = parts.length > 1 ? parts.slice(1).join('/') : fullName; + + const url = `${BASE}/packages/${fullName}.json`; + const data = await fetchJson(url, indexer.httpOpts); + + // Find the version in the versions map + const versionData = data.package.versions[version] + || data.package.versions[`v${version}`]; + + if (!versionData) { + throw new Error(`Version ${version} not found for ${fullName}`); + } + + if (!versionData.dist?.url) { + throw new Error(`No dist URL for ${fullName}@${version}`); + } + + const distUrl = versionData.dist.url; + const ext = versionData.dist.type === 'zip' ? 'zip' : 'tar.gz'; + const filename = `${shortName}-${version}.${ext}`; + + await indexer.downloadVersion(distUrl, shortName, version, filename, vendor); + } + + // -- internal -- + + private async fetchSinglePackage(indexer: Indexer, fullName: string): Promise { + const url = `${BASE}/packages/${fullName}.json`; + const data = await fetchJson(url, indexer.httpOpts); + const pkg = data.package; + + const versionKeys = Object.keys(pkg.versions || {}); + // Filter out dev versions for the "latest" pick + const stableVersions = versionKeys.filter(v => !v.includes('dev')); + const latestVersion = stableVersions[0] || versionKeys[0]; + const latestData = latestVersion ? pkg.versions[latestVersion] : undefined; + + const parts = fullName.split('/'); + const vendor = parts[0]; + const shortName = parts.slice(1).join('/'); + + const entry: PackageEntry = { + name: shortName || fullName, + scope: vendor, + version: latestVersion, + versions: versionKeys, + description: pkg.description, + homepage: latestData?.homepage, + repository: pkg.repository, + license: latestData?.license?.[0], + downloads: pkg.downloads?.total, + updatedAt: pkg.time, + raw: pkg, + }; + + await indexer.addPackage(entry, pkg); + return entry; + } +} diff --git a/@ether/library/mirror/src/adapters/pub-dev.ts b/@ether/library/mirror/src/adapters/pub-dev.ts new file mode 100644 index 00000000..a8b68309 --- /dev/null +++ b/@ether/library/mirror/src/adapters/pub-dev.ts @@ -0,0 +1,199 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * pub.dev registry adapter (Dart/Flutter packages). + * + * API docs: https://pub.dev/help/api + * + * ~50K packages. Paginated API with `nextUrl` field for cursor-based pagination. + * Archives served as tar.gz from pub.dev. + */ + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['pub-dev']; + +const API_BASE = 'https://pub.dev/api'; +const CHECKPOINT_EVERY = 10; // checkpoint every N pages + +interface PubPackageListItem { + name: string; +} + +interface PubPackageListResponse { + packages: PubPackageListItem[]; + nextUrl?: string; +} + +interface PubPackageDetail { + name: string; + latest?: { + version: string; + pubspec?: { + name?: string; + description?: string; + homepage?: string; + repository?: string; + version?: string; + }; + archive_url?: string; + }; + versions?: Array<{ + version: string; + archive_url?: string; + published?: string; + }>; +} + +function toPackageEntry(pkg: PubPackageDetail): PackageEntry { + return { + name: pkg.name, + version: pkg.latest?.version, + versions: pkg.versions?.map(v => v.version), + description: pkg.latest?.pubspec?.description, + homepage: pkg.latest?.pubspec?.homepage, + repository: pkg.latest?.pubspec?.repository, + updatedAt: pkg.versions?.[0]?.published, + raw: pkg, + }; +} + +function toBasicEntry(item: PubPackageListItem): PackageEntry { + return { + name: item.name, + }; +} + +export class PubDevAdapter implements RegistryAdapter { + platform = platform; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + // Resume from cursor (nextUrl or page number) + const cursor = indexer.getCursor(); + let nextUrl: string | null = typeof cursor === 'string' && cursor.startsWith('http') + ? cursor + : `${API_BASE}/packages?page=${typeof cursor === 'number' ? cursor : 1}`; + + let pageNum = 0; + + while (nextUrl) { + console.log(` [pub-dev] Fetching ${nextUrl}...`); + pageNum++; + + let response: PubPackageListResponse; + try { + response = await fetchJson(nextUrl, indexer.httpOpts); + } catch (err) { + await indexer.setError(`Failed at ${nextUrl}: ${err instanceof Error ? err.message : String(err)}`); + throw err; + } + + if (!response.packages || response.packages.length === 0) break; + + for (const item of response.packages) { + // Fetch full package details for each listed package + try { + const detail = await fetchJson( + `${API_BASE}/packages/${encodeURIComponent(item.name)}`, + indexer.httpOpts + ); + const entry = toPackageEntry(detail); + await indexer.addPackage(entry, detail); + yield entry; + } catch (err) { + // Log and continue on individual package failures + console.error(` [pub-dev] Failed to fetch ${item.name}: ${err instanceof Error ? err.message : String(err)}`); + const entry = toBasicEntry(item); + await indexer.addPackage(entry); + yield entry; + } + } + + if (pageNum % CHECKPOINT_EVERY === 0) { + await indexer.checkpoint(response.nextUrl ?? pageNum); + } + + nextUrl = response.nextUrl ?? null; + } + + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // pub.dev doesn't have a dedicated "changed since" endpoint. + // We paginate from page 1 (default sort is by most recently updated) + // and stop when we encounter packages older than our last sync. + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + const lastSync = indexer.getState().lastSync; + let page = 1; + + while (true) { + const url = `${API_BASE}/packages?page=${page}`; + console.log(` [pub-dev] Incremental page ${page}...`); + + let response: PubPackageListResponse; + try { + response = await fetchJson(url, indexer.httpOpts); + } catch (err) { + await indexer.setError(`Incremental failed at page ${page}: ${err instanceof Error ? err.message : String(err)}`); + throw err; + } + + if (!response.packages || response.packages.length === 0) break; + + let foundOld = false; + for (const item of response.packages) { + try { + const detail = await fetchJson( + `${API_BASE}/packages/${encodeURIComponent(item.name)}`, + indexer.httpOpts + ); + // Check if this package is older than our last sync + const latestPublished = detail.versions?.[0]?.published; + if (lastSync && latestPublished && latestPublished < lastSync) { + foundOld = true; + break; + } + const entry = toPackageEntry(detail); + await indexer.addPackage(entry, detail); + yield entry; + } catch (err) { + console.error(` [pub-dev] Failed to fetch ${item.name}: ${err instanceof Error ? err.message : String(err)}`); + } + } + + if (foundOld) break; + if (!response.nextUrl) break; + + page++; + await indexer.checkpoint(page); + } + + await indexer.finish(); + } + + async fetchPackage(indexer: Indexer, name: string): Promise { + const url = `${API_BASE}/packages/${encodeURIComponent(name)}`; + console.log(` [pub-dev] Fetching package ${name}...`); + + const pkg = await fetchJson(url, indexer.httpOpts); + const entry = toPackageEntry(pkg); + await indexer.addPackage(entry, pkg); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string): Promise { + const url = `https://pub.dev/api/archives/${encodeURIComponent(name)}/versions/${encodeURIComponent(version)}.tar.gz`; + const filename = `${name}-${version}.tar.gz`; + console.log(` [pub-dev] Downloading ${name}@${version}...`); + + await indexer.downloadVersion(url, name, version, filename); + } +} diff --git a/@ether/library/mirror/src/adapters/pypi.ts b/@ether/library/mirror/src/adapters/pypi.ts new file mode 100644 index 00000000..3a474f19 --- /dev/null +++ b/@ether/library/mirror/src/adapters/pypi.ts @@ -0,0 +1,248 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson, httpGet } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * PyPI package registry adapter (Python). + * + * API endpoints: + * - Simple index (JSON): GET https://pypi.org/simple/ with Accept: application/vnd.pypi.simple.v1+json + * - Per-package: GET https://pypi.org/pypi/{name}/json + * - RSS updates: GET https://pypi.org/rss/updates.xml + * - Download: URLs found in the per-package JSON (urls array) + * + * ~500K packages. No proper cursor API, but the Simple Index gives a full list. + * Incremental uses the RSS feed for recently updated packages. + */ + +const BASE = 'https://pypi.org'; + +interface PyPISimpleIndex { + projects: { name: string }[]; +} + +interface PyPIPackageJson { + info: { + name: string; + version: string; + summary?: string; + description?: string; + home_page?: string; + project_url?: string; + project_urls?: Record; + license?: string; + author?: string; + author_email?: string; + package_url?: string; + requires_python?: string; + keywords?: string; + }; + releases: Record; + urls: PyPIRelease[]; +} + +interface PyPIRelease { + filename: string; + url: string; + size: number; + digests: { md5?: string; sha256?: string }; + packagetype: string; + python_version?: string; + requires_python?: string; + upload_time_iso_8601?: string; +} + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['pypi']; + +export class PyPIAdapter implements RegistryAdapter { + platform = REGISTRY_PLATFORMS['pypi']; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + // Fetch all package names using the JSON Simple API + const names = await this.fetchAllNames(indexer); + + // Resume from cursor (index into names array) + const cursor = indexer.getCursor(); + let startIdx = typeof cursor === 'number' ? cursor : 0; + + for (let i = startIdx; i < names.length; i++) { + const name = names[i]; + + try { + const entry = await this.fetchSinglePackage(indexer, name); + yield entry; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(` [pypi] Error fetching ${name}: ${msg}`); + } + + if ((i + 1) % 100 === 0) { + await indexer.checkpoint(i + 1); + } + } + + await indexer.checkpoint(names.length); + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + const cursor = indexer.getCursor(); + if (cursor === null || cursor === 0) { + // No previous sync — full enumeration + yield* this.enumerate(indexer); + return; + } + + // Fetch the RSS updates feed to find recently changed packages + const rssUrl = `${BASE}/rss/updates.xml`; + const res = await httpGet(rssUrl, indexer.httpOpts); + + if (res.status !== 200) { + console.error(` [pypi] RSS feed returned ${res.status}, falling back to full enumeration`); + yield* this.enumerate(indexer); + return; + } + + // Parse package names from RSS XML (simple regex extraction) + const packageNames = this.parseRssPackageNames(res.body); + const seen = new Set(); + let count = 0; + + for (const name of packageNames) { + if (seen.has(name)) continue; + seen.add(name); + + try { + const entry = await this.fetchSinglePackage(indexer, name); + yield entry; + count++; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(` [pypi] Error fetching ${name}: ${msg}`); + } + } + + // After incremental, checkpoint with the full count so next full resumes correctly + // We keep the original cursor format (index) so full enum can skip already-indexed + await indexer.checkpoint(cursor); + await indexer.finish(); + } + + async fetchPackage(indexer: Indexer, name: string, _scope?: string): Promise { + return this.fetchSinglePackage(indexer, name); + } + + async downloadVersion(indexer: Indexer, name: string, version: string, _scope?: string): Promise { + const url = `${BASE}/pypi/${encodeURIComponent(name)}/json`; + const data = await fetchJson(url, indexer.httpOpts); + + // Use canonical name from API to match what fetchPackage stores + const canonicalName = data.info.name; + + const releases = data.releases[version]; + if (!releases || releases.length === 0) { + throw new Error(`No release files for ${canonicalName}@${version}`); + } + + // Prefer sdist (source distribution), then bdist_wheel, then first available + const sdist = releases.find(r => r.packagetype === 'sdist'); + const wheel = releases.find(r => r.packagetype === 'bdist_wheel'); + const chosen = sdist || wheel || releases[0]; + + await indexer.downloadVersion(chosen.url, canonicalName, version, chosen.filename); + } + + // -- internal -- + + private async fetchAllNames(indexer: Indexer): Promise { + // Try the JSON Simple API first (PEP 691) + try { + const data = await fetchJson(`${BASE}/simple/`, { + ...indexer.httpOpts, + headers: { + ...indexer.httpOpts.headers, + Accept: 'application/vnd.pypi.simple.v1+json', + }, + }); + return data.projects.map(p => p.name); + } catch { + // Fall back to HTML parsing + } + + // Fallback: fetch HTML Simple Index and parse links + const res = await httpGet(`${BASE}/simple/`, indexer.httpOpts); + if (res.status !== 200) { + throw new Error(`PyPI simple index returned HTTP ${res.status}`); + } + + const names: string[] = []; + // Extract package names from {name} links + const linkRegex = /]*href="\/simple\/([^/"]+)\/"[^>]*>/g; + let match: RegExpExecArray | null; + while ((match = linkRegex.exec(res.body)) !== null) { + names.push(decodeURIComponent(match[1])); + } + + return names; + } + + private async fetchSinglePackage(indexer: Indexer, name: string): Promise { + const url = `${BASE}/pypi/${encodeURIComponent(name)}/json`; + const data = await fetchJson(url, indexer.httpOpts); + const info = data.info; + + const versions = Object.keys(data.releases || {}); + + // Find homepage from project_urls or home_page + let homepage = info.home_page || undefined; + if (!homepage && info.project_urls) { + homepage = info.project_urls['Homepage'] + || info.project_urls['Home'] + || info.project_urls['homepage'] + || Object.values(info.project_urls)[0]; + } + + // Find repository URL + let repository: string | undefined; + if (info.project_urls) { + repository = info.project_urls['Source'] + || info.project_urls['Source Code'] + || info.project_urls['Repository'] + || info.project_urls['Code']; + } + + const entry: PackageEntry = { + name: info.name, + version: info.version, + versions, + description: info.summary, + homepage, + repository, + license: info.license || undefined, + updatedAt: data.urls?.[0]?.upload_time_iso_8601, + raw: data, + }; + + await indexer.addPackage(entry, data); + return entry; + } + + private parseRssPackageNames(xml: string): string[] { + const names: string[] = []; + // Extract from https://pypi.org/project/{name}/{version}/ + const linkRegex = /https:\/\/pypi\.org\/project\/([^/]+)\/[^<]*<\/link>/g; + let match: RegExpExecArray | null; + while ((match = linkRegex.exec(xml)) !== null) { + names.push(decodeURIComponent(match[1])); + } + return names; + } +} diff --git a/@ether/library/mirror/src/adapters/register.ts b/@ether/library/mirror/src/adapters/register.ts new file mode 100644 index 00000000..7cba1ea6 --- /dev/null +++ b/@ether/library/mirror/src/adapters/register.ts @@ -0,0 +1,113 @@ +import { registerRegistryAdapter, registerVCSAdapter } from './adapter.js'; + +// -- Registry adapters (19) -- +registerRegistryAdapter('npm', async () => { + const { NpmAdapter } = await import('./npm.js'); + return new NpmAdapter(); +}); + +registerRegistryAdapter('pypi', async () => { + const { PyPIAdapter } = await import('./pypi.js'); + return new PyPIAdapter(); +}); + +registerRegistryAdapter('crates-io', async () => { + const { CratesIoAdapter } = await import('./crates-io.js'); + return new CratesIoAdapter(); +}); + +registerRegistryAdapter('maven', async () => { + const { MavenAdapter } = await import('./maven.js'); + return new MavenAdapter(); +}); + +registerRegistryAdapter('nuget', async () => { + const { NuGetAdapter } = await import('./nuget.js'); + return new NuGetAdapter(); +}); + +registerRegistryAdapter('rubygems', async () => { + const { RubyGemsAdapter } = await import('./rubygems.js'); + return new RubyGemsAdapter(); +}); + +registerRegistryAdapter('go', async () => { + const { GoAdapter } = await import('./go.js'); + return new GoAdapter(); +}); + +registerRegistryAdapter('hackage', async () => { + const { HackageAdapter } = await import('./hackage.js'); + return new HackageAdapter(); +}); + +registerRegistryAdapter('hex', async () => { + const { HexAdapter } = await import('./hex.js'); + return new HexAdapter(); +}); + +registerRegistryAdapter('pub-dev', async () => { + const { PubDevAdapter } = await import('./pub-dev.js'); + return new PubDevAdapter(); +}); + +registerRegistryAdapter('cpan', async () => { + const { CpanAdapter } = await import('./cpan.js'); + return new CpanAdapter(); +}); + +registerRegistryAdapter('cran', async () => { + const { CranAdapter } = await import('./cran.js'); + return new CranAdapter(); +}); + +registerRegistryAdapter('packagist', async () => { + const { PackagistAdapter } = await import('./packagist.js'); + return new PackagistAdapter(); +}); + +registerRegistryAdapter('cocoapods', async () => { + const { CocoaPodsAdapter } = await import('./cocoapods.js'); + return new CocoaPodsAdapter(); +}); + +registerRegistryAdapter('conda', async () => { + const { CondaAdapter } = await import('./conda.js'); + return new CondaAdapter(); +}); + +registerRegistryAdapter('opam', async () => { + const { OpamAdapter } = await import('./opam.js'); + return new OpamAdapter(); +}); + +registerRegistryAdapter('clojars', async () => { + const { ClojarsAdapter } = await import('./clojars.js'); + return new ClojarsAdapter(); +}); + +registerRegistryAdapter('luarocks', async () => { + const { LuaRocksAdapter } = await import('./luarocks.js'); + return new LuaRocksAdapter(); +}); + +registerRegistryAdapter('nimble', async () => { + const { NimbleAdapter } = await import('./nimble.js'); + return new NimbleAdapter(); +}); + +// -- VCS adapters (3) -- +registerVCSAdapter('GitHub', async () => { + const { GitHubAdapter } = await import('./github.js'); + return new GitHubAdapter(); +}); + +registerVCSAdapter('GitLab', async () => { + const { GitLabAdapter } = await import('./gitlab.js'); + return new GitLabAdapter(); +}); + +registerVCSAdapter('Bitbucket', async () => { + const { BitbucketAdapter } = await import('./bitbucket.js'); + return new BitbucketAdapter(); +}); diff --git a/@ether/library/mirror/src/adapters/rubygems.ts b/@ether/library/mirror/src/adapters/rubygems.ts new file mode 100644 index 00000000..f80ca2c2 --- /dev/null +++ b/@ether/library/mirror/src/adapters/rubygems.ts @@ -0,0 +1,274 @@ +import type { PlatformConfig, PackageEntry } from '../core/types.js'; +import type { Indexer } from '../core/indexer.js'; +import { REGISTRY_PLATFORMS } from '../core/registry-map.js'; +import { fetchJson, httpGet } from '../core/http.js'; +import type { RegistryAdapter } from './adapter.js'; + +/** + * RubyGems registry adapter (Ruby gems). + * + * API docs: https://guides.rubygems.org/rubygems-org-api/ + * + * ~180K gems. Multiple enumeration strategies: + * - Full: paginated search API (GET /api/v1/search.json?query=&page=N) + * - Incremental: GET /api/v1/activity/latest.json (50 most recently pushed) + * and GET /api/v1/activity/just_updated.json (50 most recently updated) + * - Per-gem: GET /api/v1/gems/{name}.json + * - Versions: GET /api/v1/versions/{name}.json + * - Tarballs: GET /gems/{name}-{version}.gem + * + * Rate limit: 10 req / 10s (per platform config). + */ + +export const platform: PlatformConfig = REGISTRY_PLATFORMS['rubygems']; + +const API_BASE = 'https://rubygems.org/api/v1'; +const GEM_BASE = 'https://rubygems.org'; +const SEARCH_PAGE_SIZE = 30; // RubyGems search returns 30 per page by default +const CHECKPOINT_EVERY = 10; // checkpoint every N pages + +interface GemSearchItem { + name: string; + version?: string; + version_downloads?: number; + downloads?: number; + info?: string; + homepage_uri?: string; + source_code_uri?: string; + project_uri?: string; + licenses?: string[]; +} + +interface GemDetail { + name: string; + version?: string; + version_downloads?: number; + downloads?: number; + info?: string; + homepage_uri?: string; + source_code_uri?: string; + project_uri?: string; + gem_uri?: string; + licenses?: string[]; + metadata?: Record; + created_at?: string; + updated_at?: string; // not in older API responses +} + +interface GemVersionInfo { + number: string; + created_at?: string; + summary?: string; + platform?: string; + licenses?: string[]; + prerelease?: boolean; + yanked?: boolean; + sha?: string; + downloads_count?: number; +} + +interface ActivityItem { + name: string; + version?: string; + info?: string; + homepage_uri?: string; + source_code_uri?: string; + licenses?: string[]; + downloads?: number; +} + +function toPackageEntry(gem: GemDetail | GemSearchItem, versions?: string[]): PackageEntry { + return { + name: gem.name, + version: gem.version, + versions, + description: gem.info, + homepage: gem.homepage_uri, + repository: gem.source_code_uri, + license: gem.licenses?.[0], + downloads: gem.downloads, + raw: gem, + }; +} + +export class RubyGemsAdapter implements RegistryAdapter { + platform = platform; + + async *enumerate(indexer: Indexer): AsyncGenerator { + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + // Use the Bundler compact index which returns ALL gem names AND versions + // in a single request. Format after "---" header: + // gem_name version1,version2,version3 + const res = await httpGet('https://index.rubygems.org/versions', { + ...indexer.httpOpts, + timeout: 120_000, // large file, allow extra time + }); + + if (res.status !== 200) { + throw new Error(`RubyGems compact index returned HTTP ${res.status}`); + } + + const lines = res.body.split('\n'); + let headerDone = false; + + // Parse all gems with their versions + const gems: { name: string; versions: string[] }[] = []; + for (const line of lines) { + if (!headerDone) { + if (line.trim() === '---') headerDone = true; + continue; + } + const trimmed = line.trim(); + if (!trimmed) continue; + + // Format: "gem_name version1,version2,version3 checksum" + // or just: "gem_name version1,version2" + const spaceIdx = trimmed.indexOf(' '); + if (spaceIdx === -1) continue; + + const name = trimmed.substring(0, spaceIdx); + const rest = trimmed.substring(spaceIdx + 1); + // Versions are comma-separated; there may be a trailing checksum after space + const versionsStr = rest.split(' ')[0]; + const versions = versionsStr.split(',').filter(v => v.length > 0); + + gems.push({ name, versions }); + } + + const cursor = indexer.getCursor(); + const startIdx = typeof cursor === 'number' ? cursor : 0; + let count = startIdx; + + for (let i = startIdx; i < gems.length; i++) { + const { name, versions } = gems[i]; + const latestVersion = versions[versions.length - 1]; + + const entry: PackageEntry = { + name, + version: latestVersion, + versions, + raw: { name, versions }, + }; + + await indexer.addPackage(entry, { name, versions }); + yield entry; + + count++; + if (count % 1000 === 0) { + await indexer.checkpoint(count); + } + } + + await indexer.checkpoint(count); + await indexer.finish(); + } + + async *enumerateIncremental(indexer: Indexer): AsyncGenerator { + // Use the activity endpoints to get recently published/updated gems. + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + const seen = new Set(); + + // Fetch latest published gems + console.log(' [rubygems] Fetching latest published gems...'); + try { + const latest = await fetchJson( + `${API_BASE}/activity/latest.json`, + indexer.httpOpts + ); + for (const gem of latest) { + if (seen.has(gem.name)) continue; + seen.add(gem.name); + + // Fetch full details + try { + const detail = await fetchJson( + `${API_BASE}/gems/${encodeURIComponent(gem.name)}.json`, + indexer.httpOpts + ); + const entry = toPackageEntry(detail); + await indexer.addPackage(entry, detail); + yield entry; + } catch (err) { + console.error(` [rubygems] Failed to fetch ${gem.name}: ${err instanceof Error ? err.message : String(err)}`); + const entry = toPackageEntry(gem as GemSearchItem); + await indexer.addPackage(entry); + yield entry; + } + } + } catch (err) { + console.error(` [rubygems] Failed to fetch latest activity: ${err instanceof Error ? err.message : String(err)}`); + } + + // Fetch just-updated gems + console.log(' [rubygems] Fetching just-updated gems...'); + try { + const updated = await fetchJson( + `${API_BASE}/activity/just_updated.json`, + indexer.httpOpts + ); + for (const gem of updated) { + if (seen.has(gem.name)) continue; + seen.add(gem.name); + + try { + const detail = await fetchJson( + `${API_BASE}/gems/${encodeURIComponent(gem.name)}.json`, + indexer.httpOpts + ); + const entry = toPackageEntry(detail); + await indexer.addPackage(entry, detail); + yield entry; + } catch (err) { + console.error(` [rubygems] Failed to fetch ${gem.name}: ${err instanceof Error ? err.message : String(err)}`); + const entry = toPackageEntry(gem as GemSearchItem); + await indexer.addPackage(entry); + yield entry; + } + } + } catch (err) { + console.error(` [rubygems] Failed to fetch updated activity: ${err instanceof Error ? err.message : String(err)}`); + } + + await indexer.finish(); + } + + async fetchPackage(indexer: Indexer, name: string): Promise { + console.log(` [rubygems] Fetching gem ${name}...`); + + // Fetch gem metadata + const gem = await fetchJson( + `${API_BASE}/gems/${encodeURIComponent(name)}.json`, + indexer.httpOpts + ); + + // Fetch version list + let versions: string[] | undefined; + try { + const versionList = await fetchJson( + `${API_BASE}/versions/${encodeURIComponent(name)}.json`, + indexer.httpOpts + ); + versions = versionList + .filter(v => !v.yanked) + .map(v => v.number); + } catch { + // Version list may fail; continue with just the gem detail + } + + const entry = toPackageEntry(gem, versions); + await indexer.addPackage(entry, gem); + return entry; + } + + async downloadVersion(indexer: Indexer, name: string, version: string): Promise { + const url = `${GEM_BASE}/gems/${encodeURIComponent(name)}-${encodeURIComponent(version)}.gem`; + const filename = `${name}-${version}.gem`; + console.log(` [rubygems] Downloading ${name}@${version}...`); + + await indexer.downloadVersion(url, name, version, filename); + } +} diff --git a/@ether/library/mirror/src/cli.ts b/@ether/library/mirror/src/cli.ts new file mode 100644 index 00000000..f9d89915 --- /dev/null +++ b/@ether/library/mirror/src/cli.ts @@ -0,0 +1,745 @@ +import path from 'node:path'; +import type { PackageEntry } from './core/types.js'; +import { Indexer } from './core/indexer.js'; +import { RateLimiter } from './core/rate-limit.js'; +import { loadState } from './core/state.js'; +import { Display } from './core/display.js'; +import { + REGISTRY_PLATFORMS, VCS_PLATFORMS, + LANGUAGE_TO_REGISTRY, + allRegistries, allVCS, + registryMappingTable, resolvePlatform, +} from './core/registry-map.js'; +import { + getRegistryAdapter, getVCSAdapter, + allRegistryAdapterIds, allVCSAdapterIds, +} from './adapters/adapter.js'; + +// Register all adapters +import './adapters/register.js'; + +// -- Path configuration -- +// All paths are relative to the repo root (4 levels up from this file's dir) +const MIRROR_DIR = path.dirname(new URL(import.meta.url).pathname); +const REPO_ROOT = path.resolve(MIRROR_DIR, '..', '..', '..', '..'); +const DATA_ROOT = path.join(REPO_ROOT, '.ether', '@'); +const DATABASE_ROOT = path.join(REPO_ROOT, '@ether', 'library', 'Database'); +const STATE_ROOT = path.join(REPO_ROOT, '.ether', 'mirror-state'); + +async function createIndexer(platformId: string): Promise { + const platform = resolvePlatform(platformId); + const indexer = await Indexer.create(platformId, DATA_ROOT, DATABASE_ROOT, STATE_ROOT); + if (platform?.rateLimit) { + indexer.httpOpts.rateLimiter = new RateLimiter(platform.rateLimit.requests, platform.rateLimit.windowMs); + } + return indexer; +} + +/** Build a label map: platform ID → human-readable name */ +function buildLabels(ids: string[]): Record { + const labels: Record = {}; + for (const id of ids) { + const p = resolvePlatform(id); + labels[id] = p?.name ?? id; + } + return labels; +} + +// -- Parallel execution with Display -- + +interface ParallelResult { + id: string; + ok: boolean; + error?: string; + count?: number; +} + +/** + * Run a task for each platform ID concurrently with a Display. + */ +async function runParallel( + ids: string[], + taskFn: (id: string, display: Display) => Promise, + header: string, + concurrency = 8, +): Promise { + const display = new Display({ + header, + concurrency, + ids, + labels: buildLabels(ids), + }); + display.start(); + + let idx = 0; + + async function worker(): Promise { + while (idx < ids.length) { + const i = idx++; + const id = ids[i]; + display.startTask(id); + const result = await taskFn(id, display); + if (result.ok) { + display.completeTask(id, result.count ?? 0); + } else { + display.failTask(id, result.error ?? 'Unknown error'); + } + } + } + + const workers = Array.from({ length: Math.min(concurrency, ids.length) }, () => worker()); + await Promise.all(workers); + + display.stop(); +} + +interface RunOneOpts { + display?: Display; + download?: boolean; +} + +/** + * Run a single platform sync/update, wiring indexer.onProgress to the display. + * When download=true, downloads ALL version tarballs for each package. + * If enumerate didn't provide version list, calls fetchPackage() to get it. + */ +async function runOne( + mode: 'registry-sync' | 'registry-update' | 'vcs-sync', + platformId: string, + opts: RunOneOpts = {}, +): Promise { + const { display, download } = opts; + try { + if (mode === 'registry-sync' || mode === 'registry-update') { + const adapter = await getRegistryAdapter(platformId); + if (!adapter) return { id: platformId, ok: false, error: 'No adapter found' }; + const indexer = await createIndexer(platformId); + if (display) { + indexer.onProgress = (count, current) => display.updateProgress(platformId, count, current); + } + const isIncremental = mode === 'registry-update'; + let count = 0; + const gen = isIncremental + ? adapter.enumerateIncremental(indexer) + : adapter.enumerate(indexer); + for await (const entry of gen) { + count++; + if (download) { + await downloadAllVersions(adapter, indexer, entry); + } + } + return { id: platformId, ok: true, count }; + } else { + const adapter = await getVCSAdapter(platformId); + if (!adapter) return { id: platformId, ok: false, error: 'No adapter found' }; + const indexer = await createIndexer(platformId); + if (display) { + indexer.onProgress = (count, current) => display.updateProgress(platformId, count, current); + } + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + let count = 0; + for await (const entry of adapter.enumerate(indexer)) { + count++; + if (download) { + // Clone the repo + fetch releases + try { + await adapter.cloneRepo(indexer, entry.owner, entry.name); + } catch { + // Clone failure is non-fatal — metadata was already saved + } + try { + await adapter.fetchReleases(indexer, entry.owner, entry.name); + } catch { + // Release fetch failure is non-fatal + } + } + } + await indexer.finish(); + return { id: platformId, ok: true, count }; + } + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + return { id: platformId, ok: false, error: msg }; + } +} + +/** + * Download ALL versions for a package entry. + * If entry.versions is available, downloads each one. + * If only entry.version is set, calls fetchPackage() to get the full list. + * If neither, skips downloads for this entry. + */ +async function downloadAllVersions( + adapter: { downloadVersion: (indexer: Indexer, name: string, version: string, scope?: string) => Promise; fetchPackage: (indexer: Indexer, name: string, scope?: string) => Promise }, + indexer: Indexer, + entry: PackageEntry, +): Promise { + let versions = entry.versions; + + // If enumerate didn't provide a version list, try fetchPackage to get it + if (!versions?.length) { + if (entry.version) { + // Try to get the full version list via fetchPackage + try { + const full = await adapter.fetchPackage(indexer, entry.name, entry.scope); + versions = full.versions; + } catch { + // fetchPackage failed — fall back to the single known version + } + } + // Still no versions list? Use the single version if available + if (!versions?.length && entry.version) { + versions = [entry.version]; + } + } + + if (!versions?.length) return; + + for (const v of versions) { + try { + await adapter.downloadVersion(indexer, entry.name, v, entry.scope); + } catch { + // Download failure is non-fatal — metadata was already saved + } + } +} + +// -- Commands -- + +async function cmdLanguageSync(platformId: string, dryRun = false, download = true): Promise { + const adapter = await getRegistryAdapter(platformId); + if (!adapter) { + console.error(`No adapter found for registry: ${platformId}`); + process.exit(1); + } + const indexer = await createIndexer(platformId); + console.log(`Syncing ${adapter.platform.name}${download ? ' (with downloads)' : ''}...`); + if (indexer.getCursor()) { + console.log(` Resuming from cursor: ${indexer.getCursor()}`); + } + + let count = 0; + let dlCount = 0; + try { + for await (const entry of adapter.enumerate(indexer)) { + count++; + if (dryRun) { + console.log(` [dry-run] ${entry.scope ? entry.scope + '/' : ''}${entry.name}`); + } + if (download && !dryRun) { + await downloadAllVersions(adapter, indexer, entry); + dlCount += entry.versions?.length ?? (entry.version ? 1 : 0); + } + if (count % 1000 === 0) { + console.log(` ${count} packages indexed, ${dlCount} versions downloaded...`); + } + } + console.log(`Done. ${count} packages indexed, ${dlCount} versions downloaded.`); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + await indexer.setError(msg); + console.error(`Error during sync: ${msg}`); + process.exit(1); + } +} + +async function cmdLanguageSyncAll(concurrency = 8, download = true): Promise { + const ids = allRegistryAdapterIds(); + await runParallel( + ids, + (id, display) => runOne('registry-sync', id, { display, download }), + `Syncing ${ids.length} registries (${concurrency} concurrent)`, + concurrency, + ); +} + +async function cmdLanguageUpdate(platformId: string, download = true): Promise { + const adapter = await getRegistryAdapter(platformId); + if (!adapter) { + console.error(`No adapter found for registry: ${platformId}`); + process.exit(1); + } + const indexer = await createIndexer(platformId); + console.log(`Incremental update for ${adapter.platform.name}${download ? ' (with downloads)' : ''}...`); + + let count = 0; + let dlCount = 0; + try { + for await (const entry of adapter.enumerateIncremental(indexer)) { + count++; + if (download) { + await downloadAllVersions(adapter, indexer, entry); + dlCount += entry.versions?.length ?? (entry.version ? 1 : 0); + } + if (count % 100 === 0) { + console.log(` ${count} packages updated, ${dlCount} versions downloaded...`); + } + } + console.log(`Done. ${count} packages updated, ${dlCount} versions downloaded.`); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + await indexer.setError(msg); + console.error(`Error during update: ${msg}`); + process.exit(1); + } +} + +async function cmdLanguageUpdateAll(concurrency = 8, download = true): Promise { + const ids = allRegistryAdapterIds(); + await runParallel( + ids, + (id, display) => runOne('registry-update', id, { display, download }), + `Updating ${ids.length} registries (${concurrency} concurrent)`, + concurrency, + ); +} + +async function cmdLanguageFetch(platformId: string, name: string, opts: { version?: string; scope?: string; allVersions?: boolean }): Promise { + const adapter = await getRegistryAdapter(platformId); + if (!adapter) { + console.error(`No adapter found for registry: ${platformId}`); + process.exit(1); + } + const indexer = await createIndexer(platformId); + console.log(`Fetching ${opts.scope ? opts.scope + '/' : ''}${name} from ${adapter.platform.name}...`); + + try { + const entry = await adapter.fetchPackage(indexer, name, opts.scope); + console.log(` Name: ${entry.name}`); + if (entry.description) console.log(` Description: ${entry.description}`); + if (entry.versions) console.log(` Versions: ${entry.versions.length}`); + if (entry.license) console.log(` License: ${entry.license}`); + + // Use canonical name/scope from the entry for downloads to ensure path consistency + const dlName = entry.name; + const dlScope = entry.scope ?? opts.scope; + + if (opts.allVersions && entry.versions?.length) { + // Download every version + console.log(` Downloading all ${entry.versions.length} versions...`); + let done = 0; + for (const v of entry.versions) { + try { + await adapter.downloadVersion(indexer, dlName, v, dlScope); + done++; + if (done % 10 === 0) console.log(` ${done}/${entry.versions.length}...`); + } catch (err) { + const dlMsg = err instanceof Error ? err.message : String(err); + console.error(` ${v}: ${dlMsg}`); + } + } + console.log(` Downloaded ${done}/${entry.versions.length} versions.`); + } else { + // Download specific version, or latest + const dlVersion = opts.version ?? entry.version; + if (dlVersion) { + console.log(` Downloading version ${dlVersion}...`); + try { + await adapter.downloadVersion(indexer, dlName, dlVersion, dlScope); + console.log(` Downloaded.`); + } catch (err) { + const dlMsg = err instanceof Error ? err.message : String(err); + console.error(` Download failed: ${dlMsg}`); + } + } + } + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(`Error: ${msg}`); + process.exit(1); + } +} + +async function cmdLanguageStatus(platformId?: string): Promise { + if (platformId) { + const state = await loadState(STATE_ROOT, platformId); + const platform = resolvePlatform(platformId); + console.log(`${platform?.name ?? platformId}:`); + console.log(` Phase: ${state.phase}`); + console.log(` Cursor: ${state.cursor ?? '(none)'}`); + console.log(` Indexed: ${state.totalIndexed}`); + console.log(` Last sync: ${state.lastSync ?? 'never'}`); + console.log(` Last error: ${state.lastError ?? '(none)'}`); + return; + } + + // Show all registries + console.log('Registry mirror status:\n'); + for (const p of allRegistries()) { + const state = await loadState(STATE_ROOT, p.id); + const status = state.lastSync ? `${state.totalIndexed} pkgs, last ${state.lastSync}` : 'not synced'; + console.log(` ${p.name.padEnd(20)} ${status}`); + } +} + +async function cmdLanguagePlatforms(): Promise { + console.log('Language → Registry mapping:\n'); + const table = registryMappingTable(); + const maxLang = Math.max(...table.map(r => r.language.length), 10); + const maxReg = Math.max(...table.map(r => r.registry.length), 10); + + console.log(` ${'Language'.padEnd(maxLang)} ${'Registry'.padEnd(maxReg)} Platform ID`); + console.log(` ${'─'.repeat(maxLang)} ${'─'.repeat(maxReg)} ${'─'.repeat(15)}`); + for (const row of table) { + console.log(` ${row.language.padEnd(maxLang)} ${row.registry.padEnd(maxReg)} ${row.platformId}`); + } +} + +async function cmdDatabaseSync(platformId: string, download = true): Promise { + const adapter = await getVCSAdapter(platformId); + if (!adapter) { + console.error(`No VCS adapter found for: ${platformId}`); + process.exit(1); + } + const indexer = await createIndexer(platformId); + console.log(`Syncing ${adapter.platform.name} repositories${download ? ' (with cloning)' : ''}...`); + if (indexer.getCursor()) { + console.log(` Resuming from cursor: ${indexer.getCursor()}`); + } + await indexer.setPhase('full'); + indexer.startAutoCheckpoint(); + + let count = 0; + let cloned = 0; + try { + for await (const entry of adapter.enumerate(indexer)) { + count++; + if (download) { + try { + await adapter.cloneRepo(indexer, entry.owner, entry.name); + cloned++; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(` Clone failed for ${entry.owner}/${entry.name}: ${msg}`); + } + try { + await adapter.fetchReleases(indexer, entry.owner, entry.name); + } catch { + // Release fetch failure is non-fatal + } + } + if (count % 100 === 0) { + console.log(` ${count} repos indexed, ${cloned} cloned...`); + } + } + await indexer.finish(); + console.log(`Done. ${count} repos indexed, ${cloned} cloned.`); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + await indexer.setError(msg); + console.error(`Error during sync: ${msg}`); + process.exit(1); + } +} + +async function cmdDatabaseClone(platformId: string, ownerRepo: string, releaseTag?: string): Promise { + const adapter = await getVCSAdapter(platformId); + if (!adapter) { + console.error(`No VCS adapter found for: ${platformId}`); + process.exit(1); + } + const [owner, repo] = ownerRepo.split('/'); + if (!owner || !repo) { + console.error('Usage: database-clone '); + process.exit(1); + } + const indexer = await createIndexer(platformId); + console.log(`Cloning ${owner}/${repo} from ${adapter.platform.name}...`); + + try { + await adapter.cloneRepo(indexer, owner, repo); + console.log('Clone complete.'); + + if (releaseTag) { + console.log(`Fetching release ${releaseTag}...`); + await adapter.fetchRelease(indexer, owner, repo, releaseTag); + } else { + console.log('Fetching releases...'); + await adapter.fetchReleases(indexer, owner, repo); + } + console.log('Done.'); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(`Error: ${msg}`); + process.exit(1); + } +} + +async function cmdDatabaseFetch(platformId: string, ownerRepo: string, releaseTag?: string): Promise { + const adapter = await getVCSAdapter(platformId); + if (!adapter) { + console.error(`No VCS adapter found for: ${platformId}`); + process.exit(1); + } + const [owner, repo] = ownerRepo.split('/'); + if (!owner || !repo) { + console.error('Usage: database-fetch '); + process.exit(1); + } + const indexer = await createIndexer(platformId); + console.log(`Fetching metadata for ${owner}/${repo} from ${adapter.platform.name}...`); + + try { + const entry = await adapter.fetchRepo(indexer, owner, repo); + console.log(` Name: ${entry.fullName}`); + if (entry.description) console.log(` Description: ${entry.description}`); + if (entry.language) console.log(` Language: ${entry.language}`); + if (entry.stars !== undefined) console.log(` Stars: ${entry.stars}`); + + if (releaseTag) { + console.log(`Fetching release ${releaseTag}...`); + await adapter.fetchRelease(indexer, owner, repo, releaseTag); + } + console.log('Done.'); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.error(`Error: ${msg}`); + process.exit(1); + } +} + +async function cmdDatabaseStatus(platformId?: string): Promise { + if (platformId) { + const state = await loadState(STATE_ROOT, platformId); + const platform = resolvePlatform(platformId); + console.log(`${platform?.name ?? platformId}:`); + console.log(` Phase: ${state.phase}`); + console.log(` Cursor: ${state.cursor ?? '(none)'}`); + console.log(` Indexed: ${state.totalIndexed}`); + console.log(` Last sync: ${state.lastSync ?? 'never'}`); + console.log(` Last error: ${state.lastError ?? '(none)'}`); + return; + } + + console.log('VCS mirror status:\n'); + for (const p of allVCS()) { + const state = await loadState(STATE_ROOT, p.id); + const status = state.lastSync ? `${state.totalIndexed} repos, last ${state.lastSync}` : 'not synced'; + console.log(` ${p.name.padEnd(20)} ${status}`); + } +} + +async function cmdDatabaseSyncAll(concurrency = 8, download = true): Promise { + const ids = allVCSAdapterIds(); + await runParallel( + ids, + (id, display) => runOne('vcs-sync', id, { display, download }), + `Syncing ${ids.length} VCS platforms (${concurrency} concurrent)`, + concurrency, + ); +} + +async function cmdMirrorAll(concurrency = 8, download = true): Promise { + const registryIds = allRegistryAdapterIds(); + const vcsIds = allVCSAdapterIds(); + const allIds = [ + ...registryIds.map(id => ({ id, mode: 'registry-sync' as const })), + ...vcsIds.map(id => ({ id, mode: 'vcs-sync' as const })), + ]; + const ids = allIds.map(x => x.id); + const modeMap = new Map(allIds.map(x => [x.id, x.mode])); + + await runParallel( + ids, + (id, display) => runOne(modeMap.get(id)!, id, { display, download }), + `Mirroring ${ids.length} platforms (${registryIds.length} registries + ${vcsIds.length} VCS, ${concurrency} concurrent)`, + concurrency, + ); +} + +async function cmdDaily(concurrency = 8, download = true): Promise { + const registryIds = allRegistryAdapterIds(); + const vcsIds = allVCSAdapterIds(); + const allIds = [ + ...registryIds.map(id => ({ id, mode: 'registry-update' as const })), + ...vcsIds.map(id => ({ id, mode: 'vcs-sync' as const })), + ]; + const ids = allIds.map(x => x.id); + const modeMap = new Map(allIds.map(x => [x.id, x.mode])); + + await runParallel( + ids, + (id, display) => runOne(modeMap.get(id)!, id, { display, download }), + `Daily incremental: ${registryIds.length} registries + ${vcsIds.length} VCS (${concurrency} concurrent)`, + concurrency, + ); +} + +// -- Argument parsing -- + +function parseArgs(args: string[]): { command: string; positional: string[]; flags: Record } { + const flags: Record = {}; + const positional: string[] = []; + let command = ''; + + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + if (!command && !arg.startsWith('-')) { + command = arg; + } else if (arg.startsWith('--')) { + const eq = arg.indexOf('='); + if (eq !== -1) { + flags[arg.slice(2, eq)] = arg.slice(eq + 1); + } else if (i + 1 < args.length && !args[i + 1].startsWith('-')) { + flags[arg.slice(2)] = args[i + 1]; + i++; + } else { + flags[arg.slice(2)] = true; + } + } else if (!arg.startsWith('-')) { + positional.push(arg); + } + } + + return { command, positional, flags }; +} + +// -- Main -- + +async function main(): Promise { + const args = process.argv.slice(2); + if (args.length === 0) { + printUsage(); + process.exit(0); + } + + const { command, positional, flags } = parseArgs(args); + const dryRun = flags['dry-run'] === true; + const download = flags['no-download'] !== true; + const concurrency = typeof flags['concurrency'] === 'string' ? parseInt(flags['concurrency'], 10) : 8; + + switch (command) { + case 'language-sync': + if (flags['all'] || positional[0] === 'all') { + await cmdLanguageSyncAll(concurrency, download); + } else { + const id = positional[0]; + if (!id) { console.error('Usage: language-sync '); process.exit(1); } + await cmdLanguageSync(id, dryRun, download); + } + break; + + case 'language-update': + if (flags['all'] || positional[0] === 'all') { + await cmdLanguageUpdateAll(concurrency, download); + } else { + const id = positional[0]; + if (!id) { console.error('Usage: language-update '); process.exit(1); } + await cmdLanguageUpdate(id, download); + } + break; + + case 'language-fetch': { + const id = positional[0]; + const name = positional[1]; + if (!id || !name) { console.error('Usage: language-fetch [--version V] [--scope S] [--all-versions]'); process.exit(1); } + await cmdLanguageFetch(id, name, { + version: flags['version'] as string | undefined, + scope: flags['scope'] as string | undefined, + allVersions: flags['all-versions'] === true, + }); + break; + } + + case 'language-status': + await cmdLanguageStatus(positional[0]); + break; + + case 'language-platforms': + await cmdLanguagePlatforms(); + break; + + case 'language-sync-all': + await cmdLanguageSyncAll(concurrency, download); + break; + + case 'database-sync': + if (flags['all'] || positional[0] === 'all') { + await cmdDatabaseSyncAll(concurrency, download); + } else { + const id = positional[0]; + if (!id) { console.error('Usage: database-sync '); process.exit(1); } + await cmdDatabaseSync(id, download); + } + break; + + case 'database-update': + if (flags['all'] || positional[0] === 'all') { + await cmdDatabaseSyncAll(concurrency, download); + } else { + const id = positional[0]; + if (!id) { console.error('Usage: database-update '); process.exit(1); } + await cmdDatabaseSync(id, download); + } + break; + + case 'database-clone': { + const id = positional[0]; + const ownerRepo = positional[1]; + if (!id || !ownerRepo) { console.error('Usage: database-clone '); process.exit(1); } + await cmdDatabaseClone(id, ownerRepo, flags['release'] as string | undefined); + break; + } + + case 'database-fetch': { + const id = positional[0]; + const ownerRepo = positional[1]; + if (!id || !ownerRepo) { console.error('Usage: database-fetch '); process.exit(1); } + await cmdDatabaseFetch(id, ownerRepo, flags['release'] as string | undefined); + break; + } + + case 'database-status': + await cmdDatabaseStatus(positional[0]); + break; + + case 'mirror-all': + await cmdMirrorAll(concurrency, download); + break; + + case 'daily': + await cmdDaily(concurrency, download); + break; + + default: + console.error(`Unknown command: ${command}`); + printUsage(); + process.exit(1); + } +} + +function printUsage(): void { + console.log(`ether mirror CLI + +Language registry commands: + language-sync [--dry-run] Full sync a registry + language-sync all [--concurrency N] Sync all registries in parallel + language-update Incremental update + language-update all [--concurrency N] Update all registries in parallel + language-fetch [--version V] [--scope S] [--all-versions] Fetch package + download + language-status [platform-id] Show sync status + language-platforms List language→registry mapping + +VCS commands: + database-sync Sync VCS platform + database-sync all [--concurrency N] Sync all VCS in parallel + database-update Incremental update + database-clone [--release tag] Clone repo (bare) + database-fetch [--release tag] Fetch metadata only + database-status [platform-id] Show VCS status + +Orchestration: + mirror-all [--concurrency N] Mirror EVERYTHING in parallel (default: 8) + daily [--concurrency N] Daily incremental (all platforms, parallel) + +Global flags: + --concurrency N Max concurrent tasks (default: 8) + --no-download Skip tarball/archive downloads (metadata only) +`); +} + +main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/@ether/library/mirror/src/core/display.ts b/@ether/library/mirror/src/core/display.ts new file mode 100644 index 00000000..3f18d4f8 --- /dev/null +++ b/@ether/library/mirror/src/core/display.ts @@ -0,0 +1,348 @@ +/** + * Dynamic terminal pretty-printer for parallel mirror operations. + * Zero external dependencies — ANSI escape codes via process.stdout.write. + * + * TTY mode: cursor-up-and-overwrite rendering at 80ms intervals. + * Non-TTY mode: line-by-line logging with [platform] prefixes. + */ + +const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] as const; + +// ANSI escape helpers +const ESC = '\x1b['; +const HIDE_CURSOR = `${ESC}?25l`; +const SHOW_CURSOR = `${ESC}?25h`; +const ERASE_LINE = `${ESC}2K`; +const RESET = `${ESC}0m`; +const BOLD = `${ESC}1m`; +const DIM = `${ESC}2m`; +const CYAN = `${ESC}36m`; +const GREEN = `${ESC}32m`; +const RED = `${ESC}31m`; +const GRAY = `${ESC}90m`; + +type TaskStatus = 'waiting' | 'running' | 'done' | 'error'; + +interface TaskState { + id: string; + label: string; + status: TaskStatus; + count: number; + current: string; + error: string; + startTime: number; + elapsed: number; // ms, set on completion +} + +export interface DisplayOptions { + header: string; + concurrency: number; + ids: string[]; + labels: Record; +} + +export class Display { + private tasks: Map = new Map(); + private order: string[]; // preserves insertion order for rendering + private header: string; + private concurrency: number; + private isTTY: boolean; + private renderInterval: ReturnType | null = null; + private spinnerFrame = 0; + private linesWritten = 0; + private startTime = 0; + + // Console intercept + private origLog: typeof console.log; + private origError: typeof console.error; + private origWarn: typeof console.warn; + private interceptedLines: string[] = []; + + constructor(opts: DisplayOptions) { + this.header = opts.header; + this.concurrency = opts.concurrency; + this.isTTY = process.stdout.isTTY === true; + this.order = [...opts.ids]; + this.origLog = console.log; + this.origError = console.error; + this.origWarn = console.warn; + + for (const id of opts.ids) { + this.tasks.set(id, { + id, + label: opts.labels[id] ?? id, + status: 'waiting', + count: 0, + current: '', + error: '', + startTime: 0, + elapsed: 0, + }); + } + } + + start(): void { + this.startTime = Date.now(); + + if (!this.isTTY) { + this.logLine(`${this.header}`); + return; + } + + // Hide cursor + process.stdout.write(HIDE_CURSOR); + + // Intercept console.log/error/warn to suppress adapter noise + console.log = (...args: unknown[]) => { + this.interceptedLines.push(args.map(String).join(' ')); + }; + console.error = (...args: unknown[]) => { + this.interceptedLines.push(args.map(String).join(' ')); + }; + console.warn = (...args: unknown[]) => { + this.interceptedLines.push(args.map(String).join(' ')); + }; + + // Start render loop + this.renderInterval = setInterval(() => { + this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length; + this.render(); + }, 80); + + // Clean exit on SIGINT + process.on('SIGINT', () => { + this.stop(); + process.exit(130); + }); + + // Initial render + this.render(); + } + + startTask(id: string): void { + const task = this.tasks.get(id); + if (!task) return; + task.status = 'running'; + task.startTime = Date.now(); + + if (!this.isTTY) { + this.logLine(`[${task.label}] Syncing...`); + } + } + + updateProgress(id: string, count: number, current: string): void { + const task = this.tasks.get(id); + if (!task) return; + task.count = count; + task.current = current; + } + + completeTask(id: string, count: number): void { + const task = this.tasks.get(id); + if (!task) return; + task.status = 'done'; + task.count = count; + task.elapsed = Date.now() - task.startTime; + task.current = ''; + + if (!this.isTTY) { + this.logLine(`[${task.label}] Done — ${this.fmtCount(count)} (${this.fmtTime(task.elapsed)})`); + } + } + + failTask(id: string, error: string): void { + const task = this.tasks.get(id); + if (!task) return; + task.status = 'error'; + task.error = error; + task.elapsed = Date.now() - task.startTime; + task.current = ''; + + if (!this.isTTY) { + this.logLine(`[${task.label}] Error: ${error}`); + } + } + + stop(): void { + if (this.renderInterval) { + clearInterval(this.renderInterval); + this.renderInterval = null; + } + + if (this.isTTY) { + // Final render + this.render(); + + // Restore console + console.log = this.origLog; + console.error = this.origError; + console.warn = this.origWarn; + + // Show cursor + process.stdout.write(SHOW_CURSOR); + + // Print summary below + this.origLog(''); + } + + // Print final summary + const done = [...this.tasks.values()].filter(t => t.status === 'done'); + const errors = [...this.tasks.values()].filter(t => t.status === 'error'); + const total = this.tasks.size; + const elapsed = this.fmtTime(Date.now() - this.startTime); + + if (this.isTTY) { + this.origLog(`${done.length}/${total} completed in ${elapsed}${errors.length ? `, ${RED}${errors.length} error(s)${RESET}` : ''}`); + } else { + this.logLine(`${done.length}/${total} completed in ${elapsed}${errors.length ? `, ${errors.length} error(s)` : ''}`); + } + + if (errors.length) { + for (const e of errors) { + if (this.isTTY) { + this.origLog(` ${RED}${e.label}: ${e.error}${RESET}`); + } else { + this.logLine(` ${e.label}: ${e.error}`); + } + } + } + } + + // -- Private -- + + private render(): void { + const spinner = SPINNER_FRAMES[this.spinnerFrame]; + const lines: string[] = []; + + // Header + const doneCount = [...this.tasks.values()].filter(t => t.status === 'done').length; + const errCount = [...this.tasks.values()].filter(t => t.status === 'error').length; + const runningCount = [...this.tasks.values()].filter(t => t.status === 'running').length; + + if (doneCount + errCount < this.tasks.size) { + lines.push(`${CYAN}${spinner}${RESET} ${BOLD}${this.header}${RESET}`); + } else { + lines.push(`${GREEN}✓${RESET} ${BOLD}${this.header}${RESET}`); + } + lines.push(''); + + // Determine how many lines we can show + const termRows = process.stdout.rows || 40; + // Reserve: header(1) + blank(1) + footer(1) + blank(1) + buffer(2) + const maxTaskLines = Math.max(4, termRows - 6); + + // Build task lines + const taskLines: string[] = []; + const maxLabel = Math.max(...[...this.tasks.values()].map(t => t.label.length), 6); + let waitingCount = 0; + + for (const id of this.order) { + const task = this.tasks.get(id)!; + + switch (task.status) { + case 'waiting': + waitingCount++; + // Only show waiting tasks if we have room + if (taskLines.length < maxTaskLines - 2) { // leave room for collapsed + footer + taskLines.push(` ${GRAY}○ ${task.label.padEnd(maxLabel)}${RESET} ${DIM}Waiting...${RESET}`); + } + break; + case 'running': { + const countStr = this.fmtCount(task.count); + const currentStr = task.current ? ` — ${task.current}` : ''; + taskLines.push(` ${CYAN}${spinner} ${task.label.padEnd(maxLabel)}${RESET} ${countStr}${currentStr}`); + break; + } + case 'done': { + const timeStr = this.fmtTime(task.elapsed); + taskLines.push(` ${GREEN}✓ ${task.label.padEnd(maxLabel)}${RESET} Done — ${this.fmtCount(task.count)} (${timeStr})`); + break; + } + case 'error': + taskLines.push(` ${RED}✗ ${task.label.padEnd(maxLabel)}${RESET} ${RED}Error: ${this.truncate(task.error, 60)}${RESET}`); + break; + } + } + + // If we overflowed on waiting tasks, collapse + if (taskLines.length > maxTaskLines) { + // Remove excess waiting lines from the end + const overflow = taskLines.length - maxTaskLines + 1; // +1 for the collapse line + // Find and remove waiting lines from the bottom + let removed = 0; + for (let i = taskLines.length - 1; i >= 0 && removed < overflow; i--) { + if (taskLines[i].includes('Waiting...')) { + taskLines.splice(i, 1); + removed++; + } + } + if (waitingCount > 0) { + const hiddenWaiting = waitingCount - (taskLines.filter(l => l.includes('Waiting...')).length); + if (hiddenWaiting > 0) { + taskLines.push(` ${DIM}...${hiddenWaiting} waiting${RESET}`); + } + } + } + + lines.push(...taskLines); + + // Footer + lines.push(''); + const footerParts: string[] = []; + if (doneCount > 0) footerParts.push(`${GREEN}${doneCount}${RESET} completed`); + if (runningCount > 0) footerParts.push(`${CYAN}${runningCount}${RESET} running`); + if (errCount > 0) footerParts.push(`${RED}${errCount}${RESET} error${errCount > 1 ? 's' : ''}`); + if (waitingCount > 0) footerParts.push(`${DIM}${waitingCount} waiting${RESET}`); + lines.push(` ${footerParts.join(', ')}`); + + // Build output: move cursor up, erase+write each line + let output = ''; + + // Move cursor up to overwrite previous frame + if (this.linesWritten > 0) { + output += `${ESC}${this.linesWritten}A`; + } + + for (const line of lines) { + output += `${ERASE_LINE}${line}\n`; + } + + // Clear any leftover lines from previous frame if it was taller + if (lines.length < this.linesWritten) { + for (let i = 0; i < this.linesWritten - lines.length; i++) { + output += `${ERASE_LINE}\n`; + } + // Move cursor back up for the extra cleared lines + output += `${ESC}${this.linesWritten - lines.length}A`; + } + + this.linesWritten = lines.length; + process.stdout.write(output); + } + + private logLine(msg: string): void { + this.origLog(msg); + } + + private fmtCount(n: number): string { + if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`; + if (n >= 1_000) return `${(n / 1_000).toFixed(n >= 10_000 ? 0 : 1)}k`; + return String(n); + } + + private fmtTime(ms: number): string { + if (ms < 1000) return `${ms}ms`; + const s = ms / 1000; + if (s < 60) return `${s.toFixed(1)}s`; + const m = Math.floor(s / 60); + const rem = Math.floor(s % 60); + if (m < 60) return `${m}m${rem}s`; + const h = Math.floor(m / 60); + return `${h}h${m % 60}m`; + } + + private truncate(s: string, max: number): string { + if (s.length <= max) return s; + return s.slice(0, max - 1) + '…'; + } +} diff --git a/@ether/library/mirror/src/core/http.ts b/@ether/library/mirror/src/core/http.ts new file mode 100644 index 00000000..0231063c --- /dev/null +++ b/@ether/library/mirror/src/core/http.ts @@ -0,0 +1,143 @@ +import { RateLimiter } from './rate-limit.js'; + +export interface HttpOptions { + headers?: Record; + timeout?: number; + retries?: number; + rateLimiter?: RateLimiter; +} + +export interface HttpResponse { + status: number; + headers: Record; + body: string; + json(): T; +} + +const DEFAULT_TIMEOUT = 30_000; +const DEFAULT_RETRIES = 3; +const RETRY_DELAYS = [1000, 5000, 15000]; + +/** + * HTTP client with retry, rate limiting, and raw response saving. + */ +export async function httpGet(url: string, opts: HttpOptions = {}): Promise { + const { headers = {}, timeout = DEFAULT_TIMEOUT, retries = DEFAULT_RETRIES, rateLimiter } = opts; + + for (let attempt = 0; attempt <= retries; attempt++) { + if (rateLimiter) await rateLimiter.acquire(); + + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), timeout); + + try { + const res = await fetch(url, { + headers: { 'User-Agent': 'ether-mirror/0.1', ...headers }, + signal: controller.signal, + }); + clearTimeout(timer); + + const responseHeaders: Record = {}; + res.headers.forEach((v, k) => { responseHeaders[k] = v; }); + + const body = await res.text(); + + if (res.status === 429 || (res.status >= 500 && attempt < retries)) { + const delay = RETRY_DELAYS[Math.min(attempt, RETRY_DELAYS.length - 1)]; + const retryAfter = res.headers.get('retry-after'); + const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : delay; + console.error(` HTTP ${res.status} from ${url}, retrying in ${waitMs}ms...`); + await new Promise(r => setTimeout(r, waitMs)); + continue; + } + + return { + status: res.status, + headers: responseHeaders, + body, + json(): T { return JSON.parse(body) as T; }, + }; + } catch (err: unknown) { + clearTimeout(timer); + if (attempt < retries) { + const delay = RETRY_DELAYS[Math.min(attempt, RETRY_DELAYS.length - 1)]; + const msg = err instanceof Error ? err.message : String(err); + console.error(` Request to ${url} failed (${msg}), retrying in ${delay}ms...`); + await new Promise(r => setTimeout(r, delay)); + continue; + } + throw err; + } + } + + throw new Error(`All ${retries + 1} attempts failed for ${url}`); +} + +/** + * Fetch JSON from a URL with retry + rate limiting. + */ +export async function fetchJson(url: string, opts: HttpOptions = {}): Promise { + const res = await httpGet(url, { + ...opts, + headers: { Accept: 'application/json', ...opts.headers }, + }); + if (res.status !== 200) { + throw new Error(`HTTP ${res.status} from ${url}: ${res.body.slice(0, 200)}`); + } + return res.json(); +} + +/** + * Download a binary file to disk. Returns the number of bytes written. + */ +export async function downloadFile( + url: string, + destPath: string, + opts: HttpOptions = {} +): Promise { + const { timeout = 120_000, retries = DEFAULT_RETRIES, rateLimiter, headers = {} } = opts; + const fs = await import('node:fs'); + const fsp = fs.promises; + const path = await import('node:path'); + + await fsp.mkdir(path.dirname(destPath), { recursive: true }); + + for (let attempt = 0; attempt <= retries; attempt++) { + if (rateLimiter) await rateLimiter.acquire(); + + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), timeout); + + try { + const res = await fetch(url, { + headers: { 'User-Agent': 'ether-mirror/0.1', ...headers }, + signal: controller.signal, + }); + clearTimeout(timer); + + if (res.status === 429 || (res.status >= 500 && attempt < retries)) { + const delay = RETRY_DELAYS[Math.min(attempt, RETRY_DELAYS.length - 1)]; + await new Promise(r => setTimeout(r, delay)); + continue; + } + + if (!res.ok) { + throw new Error(`HTTP ${res.status} downloading ${url}`); + } + + const buf = Buffer.from(await res.arrayBuffer()); + await fsp.writeFile(destPath, buf); + return buf.length; + } catch (err: unknown) { + clearTimeout(timer); + if (attempt < retries) { + const delay = RETRY_DELAYS[Math.min(attempt, RETRY_DELAYS.length - 1)]; + await new Promise(r => setTimeout(r, delay)); + continue; + } + throw err; + } + } + + throw new Error(`All ${retries + 1} download attempts failed for ${url}`); +} diff --git a/@ether/library/mirror/src/core/indexer.ts b/@ether/library/mirror/src/core/indexer.ts new file mode 100644 index 00000000..f01fa0a5 --- /dev/null +++ b/@ether/library/mirror/src/core/indexer.ts @@ -0,0 +1,156 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import type { PackageEntry, RepoEntry, ReleaseEntry, SyncState, DatabaseIndex } from './types.js'; +import { loadState, saveState } from './state.js'; +import { savePackageMeta, saveApiResponse, saveVersionMeta, versionTarballPath, saveRepoMeta, saveRepoApiResponse, saveReleaseMeta, releaseAssetPath } from './storage.js'; +import { downloadFile } from './http.js'; +import type { HttpOptions } from './http.js'; + +/** + * THE shared module all adapters use. + * Handles state persistence, file storage, and progress tracking. + */ +export class Indexer { + readonly platform: string; + readonly dataRoot: string; + readonly databaseRoot: string; + readonly stateRoot: string; + private state: SyncState; + private dirty = false; + private checkpointInterval: ReturnType | null = null; + httpOpts: HttpOptions = {}; + onProgress: ((count: number, current: string) => void) | null = null; + + private constructor( + platform: string, + dataRoot: string, + databaseRoot: string, + stateRoot: string, + state: SyncState + ) { + this.platform = platform; + this.dataRoot = dataRoot; + this.databaseRoot = databaseRoot; + this.stateRoot = stateRoot; + this.state = state; + } + + static async create(platform: string, dataRoot: string, databaseRoot: string, stateRoot: string): Promise { + const state = await loadState(stateRoot, platform); + return new Indexer(platform, dataRoot, databaseRoot, stateRoot, state); + } + + getState(): SyncState { + return { ...this.state }; + } + + getCursor(): string | number | null { + return this.state.cursor; + } + + // -- Package operations -- + + async addPackage(entry: PackageEntry, rawApiResponse?: unknown): Promise { + await savePackageMeta(this.dataRoot, this.platform, entry, entry.scope); + if (rawApiResponse !== undefined) { + await saveApiResponse(this.dataRoot, this.platform, entry.name, rawApiResponse, entry.scope); + } + this.state.totalIndexed++; + this.dirty = true; + this.onProgress?.(this.state.totalIndexed, entry.scope ? `${entry.scope}/${entry.name}` : entry.name); + } + + async addVersion(pkg: string, version: string, meta: unknown, scope?: string): Promise { + await saveVersionMeta(this.dataRoot, this.platform, pkg, version, meta, scope); + } + + async downloadVersion( + url: string, pkg: string, version: string, filename: string, scope?: string + ): Promise { + const dest = versionTarballPath(this.dataRoot, this.platform, pkg, version, filename, scope); + return downloadFile(url, dest, this.httpOpts); + } + + // -- Repo operations -- + + async addRepo(entry: RepoEntry, rawApiResponse?: unknown): Promise { + await saveRepoMeta(this.dataRoot, this.platform, entry.owner, entry.name, entry); + if (rawApiResponse !== undefined) { + await saveRepoApiResponse(this.dataRoot, this.platform, entry.owner, entry.name, rawApiResponse); + } + this.state.totalIndexed++; + this.dirty = true; + this.onProgress?.(this.state.totalIndexed, `${entry.owner}/${entry.name}`); + } + + async addRelease(owner: string, repo: string, release: ReleaseEntry): Promise { + await saveReleaseMeta(this.dataRoot, this.platform, owner, repo, release); + } + + async downloadReleaseAsset( + url: string, owner: string, repo: string, tag: string, filename: string + ): Promise { + const dest = releaseAssetPath(this.dataRoot, this.platform, owner, repo, tag, filename); + return downloadFile(url, dest, this.httpOpts); + } + + // -- State management -- + + async checkpoint(cursor: string | number): Promise { + this.state.cursor = cursor; + this.state.lastSync = new Date().toISOString(); + this.dirty = false; + await saveState(this.stateRoot, this.platform, this.state); + } + + async setPhase(phase: SyncState['phase']): Promise { + this.state.phase = phase; + await saveState(this.stateRoot, this.platform, this.state); + } + + async setError(error: string | null): Promise { + this.state.lastError = error; + await saveState(this.stateRoot, this.platform, this.state); + } + + async finish(): Promise { + this.state.phase = 'idle'; + this.state.lastSync = new Date().toISOString(); + this.state.lastError = null; + await saveState(this.stateRoot, this.platform, this.state); + await this.writeDatabaseIndex(); + if (this.checkpointInterval) { + clearInterval(this.checkpointInterval); + this.checkpointInterval = null; + } + } + + /** + * Start periodic auto-checkpointing (every N seconds). + */ + startAutoCheckpoint(intervalMs = 30_000): void { + if (this.checkpointInterval) return; + this.checkpointInterval = setInterval(async () => { + if (this.dirty && this.state.cursor !== null) { + await saveState(this.stateRoot, this.platform, this.state); + this.dirty = false; + } + }, intervalMs); + } + + /** + * Write the Database//index.json summary. + */ + async writeDatabaseIndex(): Promise { + const indexDir = path.join(this.databaseRoot, this.platform); + await fs.mkdir(indexDir, { recursive: true }); + const index: DatabaseIndex = { + platform: this.platform, + kind: 'registry', // overridden by VCS adapters + totalPackages: this.state.totalIndexed, + lastSync: this.state.lastSync, + cursor: this.state.cursor, + }; + await fs.writeFile(path.join(indexDir, 'index.json'), JSON.stringify(index, null, 2) + '\n'); + } +} diff --git a/@ether/library/mirror/src/core/rate-limit.ts b/@ether/library/mirror/src/core/rate-limit.ts new file mode 100644 index 00000000..9755e295 --- /dev/null +++ b/@ether/library/mirror/src/core/rate-limit.ts @@ -0,0 +1,36 @@ +/** + * Token-bucket rate limiter. + */ +export class RateLimiter { + private tokens: number; + private lastRefill: number; + private readonly maxTokens: number; + private readonly refillRate: number; // tokens per ms + + constructor(requests: number, windowMs: number) { + this.maxTokens = requests; + this.tokens = requests; + this.refillRate = requests / windowMs; + this.lastRefill = Date.now(); + } + + private refill(): void { + const now = Date.now(); + const elapsed = now - this.lastRefill; + this.tokens = Math.min(this.maxTokens, this.tokens + elapsed * this.refillRate); + this.lastRefill = now; + } + + async acquire(): Promise { + this.refill(); + if (this.tokens >= 1) { + this.tokens -= 1; + return; + } + // Wait until we have a token + const waitMs = Math.ceil((1 - this.tokens) / this.refillRate); + await new Promise(resolve => setTimeout(resolve, waitMs)); + this.refill(); + this.tokens -= 1; + } +} diff --git a/@ether/library/mirror/src/core/registry-map.ts b/@ether/library/mirror/src/core/registry-map.ts new file mode 100644 index 00000000..1bc8ac79 --- /dev/null +++ b/@ether/library/mirror/src/core/registry-map.ts @@ -0,0 +1,247 @@ +import type { PlatformConfig } from './types.js'; + +/** + * All known registry platforms. + */ +export const REGISTRY_PLATFORMS: Record = { + npm: { + id: 'npm', + name: 'npm', + kind: 'registry', + baseUrl: 'https://registry.npmjs.org', + rateLimit: { requests: 100, windowMs: 60_000 }, + }, + pypi: { + id: 'pypi', + name: 'PyPI', + kind: 'registry', + baseUrl: 'https://pypi.org', + rateLimit: { requests: 100, windowMs: 60_000 }, + }, + 'crates-io': { + id: 'crates-io', + name: 'crates.io', + kind: 'registry', + baseUrl: 'https://crates.io', + rateLimit: { requests: 10, windowMs: 10_000 }, + }, + maven: { + id: 'maven', + name: 'Maven Central', + kind: 'registry', + baseUrl: 'https://search.maven.org', + rateLimit: { requests: 30, windowMs: 60_000 }, + }, + nuget: { + id: 'nuget', + name: 'NuGet', + kind: 'registry', + baseUrl: 'https://api.nuget.org', + rateLimit: { requests: 100, windowMs: 60_000 }, + }, + rubygems: { + id: 'rubygems', + name: 'RubyGems', + kind: 'registry', + baseUrl: 'https://rubygems.org', + rateLimit: { requests: 10, windowMs: 10_000 }, + }, + go: { + id: 'go', + name: 'Go Module Index', + kind: 'registry', + baseUrl: 'https://index.golang.org', + rateLimit: { requests: 50, windowMs: 60_000 }, + }, + hackage: { + id: 'hackage', + name: 'Hackage', + kind: 'registry', + baseUrl: 'https://hackage.haskell.org', + rateLimit: { requests: 20, windowMs: 60_000 }, + }, + hex: { + id: 'hex', + name: 'Hex.pm', + kind: 'registry', + baseUrl: 'https://hex.pm', + rateLimit: { requests: 100, windowMs: 60_000 }, + }, + 'pub-dev': { + id: 'pub-dev', + name: 'pub.dev', + kind: 'registry', + baseUrl: 'https://pub.dev', + rateLimit: { requests: 50, windowMs: 60_000 }, + }, + cpan: { + id: 'cpan', + name: 'CPAN (MetaCPAN)', + kind: 'registry', + baseUrl: 'https://fastapi.metacpan.org', + rateLimit: { requests: 20, windowMs: 60_000 }, + }, + cran: { + id: 'cran', + name: 'CRAN', + kind: 'registry', + baseUrl: 'https://cran.r-project.org', + rateLimit: { requests: 20, windowMs: 60_000 }, + }, + packagist: { + id: 'packagist', + name: 'Packagist', + kind: 'registry', + baseUrl: 'https://packagist.org', + rateLimit: { requests: 50, windowMs: 60_000 }, + }, + cocoapods: { + id: 'cocoapods', + name: 'CocoaPods', + kind: 'registry', + baseUrl: 'https://cdn.cocoapods.org', + rateLimit: { requests: 50, windowMs: 60_000 }, + }, + conda: { + id: 'conda', + name: 'Conda', + kind: 'registry', + baseUrl: 'https://conda.anaconda.org', + rateLimit: { requests: 30, windowMs: 60_000 }, + }, + opam: { + id: 'opam', + name: 'opam', + kind: 'registry', + baseUrl: 'https://opam.ocaml.org', + rateLimit: { requests: 20, windowMs: 60_000 }, + }, + clojars: { + id: 'clojars', + name: 'Clojars', + kind: 'registry', + baseUrl: 'https://clojars.org', + rateLimit: { requests: 20, windowMs: 60_000 }, + }, + luarocks: { + id: 'luarocks', + name: 'LuaRocks', + kind: 'registry', + baseUrl: 'https://luarocks.org', + rateLimit: { requests: 20, windowMs: 60_000 }, + }, + nimble: { + id: 'nimble', + name: 'Nimble', + kind: 'registry', + baseUrl: 'https://nimble.directory', + rateLimit: { requests: 20, windowMs: 60_000 }, + }, +}; + +/** + * All known VCS platforms. + */ +export const VCS_PLATFORMS: Record = { + GitHub: { + id: 'GitHub', + name: 'GitHub', + kind: 'vcs', + baseUrl: 'https://api.github.com', + rateLimit: { requests: 30, windowMs: 60_000 }, + }, + GitLab: { + id: 'GitLab', + name: 'GitLab', + kind: 'vcs', + baseUrl: 'https://gitlab.com/api/v4', + rateLimit: { requests: 30, windowMs: 60_000 }, + }, + Bitbucket: { + id: 'Bitbucket', + name: 'Bitbucket', + kind: 'vcs', + baseUrl: 'https://api.bitbucket.org/2.0', + rateLimit: { requests: 30, windowMs: 60_000 }, + }, +}; + +/** + * Language name → registry platform ID mapping. + * Multiple languages can map to the same registry. + */ +export const LANGUAGE_TO_REGISTRY: Record = { + JavaScript: 'npm', + TypeScript: 'npm', + Python: 'pypi', + Rust: 'crates-io', + Java: 'maven', + Kotlin: 'maven', + Scala: 'maven', + 'C#': 'nuget', + CSharp: 'nuget', + 'F#': 'nuget', + FSharp: 'nuget', + Ruby: 'rubygems', + Go: 'go', + Haskell: 'hackage', + Elixir: 'hex', + Erlang: 'hex', + Dart: 'pub-dev', + Perl: 'cpan', + R: 'cran', + PHP: 'packagist', + Swift: 'cocoapods', + ObjectiveC: 'cocoapods', + Clojure: 'clojars', + Lua: 'luarocks', + OCaml: 'opam', + Nim: 'nimble', +}; + +/** + * Resolve a language name to its registry platform config. + */ +export function resolveRegistry(language: string): PlatformConfig | null { + const platformId = LANGUAGE_TO_REGISTRY[language]; + if (!platformId) return null; + return REGISTRY_PLATFORMS[platformId] ?? null; +} + +/** + * Resolve a platform ID (from either registries or VCS). + */ +export function resolvePlatform(id: string): PlatformConfig | null { + return REGISTRY_PLATFORMS[id] ?? VCS_PLATFORMS[id] ?? null; +} + +/** + * Get all registry platform configs. + */ +export function allRegistries(): PlatformConfig[] { + return Object.values(REGISTRY_PLATFORMS); +} + +/** + * Get all VCS platform configs. + */ +export function allVCS(): PlatformConfig[] { + return Object.values(VCS_PLATFORMS); +} + +/** + * Get printable mapping table: language → registry. + */ +export function registryMappingTable(): { language: string; registry: string; platformId: string }[] { + const rows: { language: string; registry: string; platformId: string }[] = []; + const seen = new Set(); + for (const [lang, platformId] of Object.entries(LANGUAGE_TO_REGISTRY)) { + const platform = REGISTRY_PLATFORMS[platformId]; + if (!platform) continue; + const key = `${lang}→${platformId}`; + if (seen.has(key)) continue; + seen.add(key); + rows.push({ language: lang, registry: platform.name, platformId }); + } + return rows; +} diff --git a/@ether/library/mirror/src/core/shard.ts b/@ether/library/mirror/src/core/shard.ts new file mode 100644 index 00000000..7c2c35d7 --- /dev/null +++ b/@ether/library/mirror/src/core/shard.ts @@ -0,0 +1,75 @@ +import path from 'node:path'; + +/** + * Shard a name into a directory path. + * Max 5 levels: first char with @ prefix, then groups of 2. + * + * "Alice" → "@A/li/ce" + * "torvalds" → "@t/or/va/ld/s" + * "AliceAliceAlice" → "@A/li/ce/Al/iceAlice" + */ +export function shardUser(name: string): string { + if (!name) return '@_'; + const parts: string[] = []; + parts.push('@' + name[0]); + let rest = name.slice(1); + for (let i = 0; i < 4 && rest.length > 0; i++) { + parts.push(rest.slice(0, 2)); + rest = rest.slice(2); + } + if (rest.length > 0) { + parts[parts.length - 1] += rest; + } + return parts.join('/'); +} + +/** + * Shard a package/repo name (no @ prefix on first segment). + * + * "express" → "e/xp/re/ss" + * "requests" → "r/eq/ue/st/s" + * "flask" → "f/la/sk" + */ +export function shardName(name: string): string { + if (!name) return '_'; + const parts: string[] = []; + parts.push(name[0]); + let rest = name.slice(1); + for (let i = 0; i < 4 && rest.length > 0; i++) { + parts.push(rest.slice(0, 2)); + rest = rest.slice(2); + } + if (rest.length > 0) { + parts[parts.length - 1] += rest; + } + return parts.join('/'); +} + +/** + * Get the storage path for a package. + * + * With scope (user exists): shard the scope, package name flat. + * .ether/@/@npm/@/@a/ng/ul/ar/core/ + * + * Without scope (no user): shard the package name. + * .ether/@/@pypi/r/eq/ue/st/s/ + */ +export function packagePath(dataRoot: string, platform: string, name: string, scope?: string): string { + const platformDir = path.join(dataRoot, '@' + platform); + if (scope) { + const bareScope = scope.startsWith('@') ? scope.slice(1) : scope; + return path.join(platformDir, '@', shardUser(bareScope), name); + } + return path.join(platformDir, shardName(name)); +} + +/** + * Get the storage path for a VCS repo. + * Shard the owner, repo name flat. + * + * .ether/@/@GitHub/@/@t/or/va/ld/s/linux/ + */ +export function repoPath(dataRoot: string, platform: string, owner: string, repo: string): string { + const platformDir = path.join(dataRoot, '@' + platform); + return path.join(platformDir, '@', shardUser(owner), repo); +} diff --git a/@ether/library/mirror/src/core/state.ts b/@ether/library/mirror/src/core/state.ts new file mode 100644 index 00000000..eb08ff85 --- /dev/null +++ b/@ether/library/mirror/src/core/state.ts @@ -0,0 +1,38 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import type { SyncState } from './types.js'; + +function statePath(stateRoot: string, platform: string): string { + return path.join(stateRoot, `${platform}.json`); +} + +export function defaultState(platform: string): SyncState { + return { + platform, + cursor: null, + lastSync: null, + phase: 'idle', + totalIndexed: 0, + lastError: null, + }; +} + +export async function loadState(stateRoot: string, platform: string): Promise { + const p = statePath(stateRoot, platform); + try { + const data = await fs.readFile(p, 'utf-8'); + return JSON.parse(data) as SyncState; + } catch { + return defaultState(platform); + } +} + +export async function saveState(stateRoot: string, platform: string, state: SyncState): Promise { + const p = statePath(stateRoot, platform); + await fs.mkdir(path.dirname(p), { recursive: true }); + await fs.writeFile(p, JSON.stringify(state, null, 2) + '\n'); +} + +export async function resetState(stateRoot: string, platform: string): Promise { + await saveState(stateRoot, platform, defaultState(platform)); +} diff --git a/@ether/library/mirror/src/core/storage.ts b/@ether/library/mirror/src/core/storage.ts new file mode 100644 index 00000000..3b162953 --- /dev/null +++ b/@ether/library/mirror/src/core/storage.ts @@ -0,0 +1,103 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { packagePath, repoPath } from './shard.js'; +import type { PackageEntry, RepoEntry, ReleaseEntry } from './types.js'; + +/** + * Save package metadata JSON. + */ +export async function savePackageMeta( + dataRoot: string, platform: string, pkg: PackageEntry, scope?: string +): Promise { + const dir = packagePath(dataRoot, platform, pkg.name, scope); + await fs.mkdir(dir, { recursive: true }); + await fs.writeFile(path.join(dir, 'meta.json'), JSON.stringify(pkg, null, 2) + '\n'); +} + +/** + * Save raw API response verbatim. + */ +export async function saveApiResponse( + dataRoot: string, platform: string, name: string, raw: unknown, scope?: string +): Promise { + const dir = packagePath(dataRoot, platform, name, scope); + await fs.mkdir(dir, { recursive: true }); + await fs.writeFile(path.join(dir, 'api-response.json'), JSON.stringify(raw, null, 2) + '\n'); +} + +/** + * Save version-specific metadata. + */ +export async function saveVersionMeta( + dataRoot: string, platform: string, name: string, + version: string, meta: unknown, scope?: string +): Promise { + const dir = path.join(packagePath(dataRoot, platform, name, scope), 'versions'); + await fs.mkdir(dir, { recursive: true }); + await fs.writeFile(path.join(dir, `${version}.meta.json`), JSON.stringify(meta, null, 2) + '\n'); +} + +/** + * Get the path where a version tarball should be stored. + */ +export function versionTarballPath( + dataRoot: string, platform: string, name: string, + version: string, filename: string, scope?: string +): string { + return path.join(packagePath(dataRoot, platform, name, scope), 'versions', filename); +} + +/** + * Save repo metadata. + */ +export async function saveRepoMeta( + dataRoot: string, platform: string, owner: string, repo: string, entry: RepoEntry +): Promise { + const dir = repoPath(dataRoot, platform, owner, repo); + await fs.mkdir(dir, { recursive: true }); + await fs.writeFile(path.join(dir, 'meta.json'), JSON.stringify(entry, null, 2) + '\n'); +} + +/** + * Save raw API response for a repo. + */ +export async function saveRepoApiResponse( + dataRoot: string, platform: string, owner: string, repo: string, raw: unknown +): Promise { + const dir = repoPath(dataRoot, platform, owner, repo); + await fs.mkdir(dir, { recursive: true }); + await fs.writeFile(path.join(dir, 'api-response.json'), JSON.stringify(raw, null, 2) + '\n'); +} + +/** + * Save release metadata. + */ +export async function saveReleaseMeta( + dataRoot: string, platform: string, owner: string, repo: string, release: ReleaseEntry +): Promise { + const dir = path.join(repoPath(dataRoot, platform, owner, repo), 'releases'); + await fs.mkdir(dir, { recursive: true }); + await fs.writeFile(path.join(dir, `${release.tag}.json`), JSON.stringify(release, null, 2) + '\n'); +} + +/** + * Get the path for a release asset download. + */ +export function releaseAssetPath( + dataRoot: string, platform: string, owner: string, repo: string, + tag: string, filename: string +): string { + return path.join(repoPath(dataRoot, platform, owner, repo), 'releases', filename); +} + +/** + * Check if a file exists. + */ +export async function exists(p: string): Promise { + try { + await fs.access(p); + return true; + } catch { + return false; + } +} diff --git a/@ether/library/mirror/src/core/types.ts b/@ether/library/mirror/src/core/types.ts new file mode 100644 index 00000000..5c337c5c --- /dev/null +++ b/@ether/library/mirror/src/core/types.ts @@ -0,0 +1,60 @@ +export interface PlatformConfig { + id: string; + name: string; + kind: 'registry' | 'vcs'; + baseUrl: string; + rateLimit?: { requests: number; windowMs: number }; +} + +export interface PackageEntry { + name: string; + scope?: string; // e.g. "@angular" for npm scoped packages + version?: string; + versions?: string[]; + description?: string; + homepage?: string; + repository?: string; + license?: string; + downloads?: number; + updatedAt?: string; + raw?: unknown; // raw API response fragment +} + +export interface RepoEntry { + owner: string; + name: string; + fullName: string; // "owner/name" + description?: string; + url: string; + defaultBranch?: string; + stars?: number; + language?: string; + updatedAt?: string; + raw?: unknown; +} + +export interface ReleaseEntry { + tag: string; + name?: string; + body?: string; + publishedAt?: string; + assets?: { name: string; url: string; size?: number }[]; + raw?: unknown; +} + +export interface SyncState { + platform: string; + cursor: string | number | null; + lastSync: string | null; + phase: 'idle' | 'full' | 'incremental'; + totalIndexed: number; + lastError: string | null; +} + +export interface DatabaseIndex { + platform: string; + kind: 'registry' | 'vcs'; + totalPackages: number; + lastSync: string | null; + cursor: string | number | null; +} diff --git a/@ether/library/mirror/src/daily.ts b/@ether/library/mirror/src/daily.ts new file mode 100644 index 00000000..250abd34 --- /dev/null +++ b/@ether/library/mirror/src/daily.ts @@ -0,0 +1,157 @@ +import type { PackageEntry } from './core/types.js'; +import { Indexer } from './core/indexer.js'; +import { RateLimiter } from './core/rate-limit.js'; +import { Display } from './core/display.js'; +import { resolvePlatform } from './core/registry-map.js'; +import { + getRegistryAdapter, getVCSAdapter, + allRegistryAdapterIds, allVCSAdapterIds, +} from './adapters/adapter.js'; +import type { RegistryAdapter } from './adapters/adapter.js'; + +interface DailyResult { + id: string; + ok: boolean; + error?: string; + count?: number; +} + +async function runOneDaily( + mode: 'registry' | 'vcs', + id: string, + dataRoot: string, + databaseRoot: string, + stateRoot: string, + display: Display, +): Promise { + try { + const platform = resolvePlatform(id); + const indexer = await Indexer.create(id, dataRoot, databaseRoot, stateRoot); + if (platform?.rateLimit) { + indexer.httpOpts.rateLimiter = new RateLimiter(platform.rateLimit.requests, platform.rateLimit.windowMs); + } + indexer.onProgress = (count, current) => display.updateProgress(id, count, current); + + await indexer.setPhase('incremental'); + indexer.startAutoCheckpoint(); + + let count = 0; + if (mode === 'registry') { + const adapter = await getRegistryAdapter(id); + if (!adapter) return { id, ok: false, error: 'No adapter found' }; + for await (const entry of adapter.enumerateIncremental(indexer)) { + count++; + await downloadAllVersionsDaily(adapter, indexer, entry); + } + } else { + const adapter = await getVCSAdapter(id); + if (!adapter) return { id, ok: false, error: 'No adapter found' }; + for await (const entry of adapter.enumerateIncremental(indexer)) { + count++; + try { + await adapter.cloneRepo(indexer, entry.owner, entry.name); + } catch { + // Clone failure is non-fatal — metadata was already saved + } + try { + await adapter.fetchReleases(indexer, entry.owner, entry.name); + } catch { + // Release fetch failure is non-fatal + } + } + } + + await indexer.finish(); + return { id, ok: true, count }; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + return { id, ok: false, error: msg }; + } +} + +/** + * Daily incremental update for all registries and VCS platforms. + * Uses Display for dynamic progress rendering. + */ +export async function runDaily(dataRoot: string, databaseRoot: string, stateRoot: string, concurrency = 8): Promise { + const registryIds = allRegistryAdapterIds(); + const vcsIds = allVCSAdapterIds(); + + const allIds = [ + ...registryIds.map(id => ({ id, mode: 'registry' as const })), + ...vcsIds.map(id => ({ id, mode: 'vcs' as const })), + ]; + const ids = allIds.map(x => x.id); + const modeMap = new Map(allIds.map(x => [x.id, x.mode])); + + const labels: Record = {}; + for (const id of ids) { + const p = resolvePlatform(id); + labels[id] = p?.name ?? id; + } + + const display = new Display({ + header: `Daily incremental: ${registryIds.length} registries + ${vcsIds.length} VCS (${concurrency} concurrent)`, + concurrency, + ids, + labels, + }); + display.start(); + + let idx = 0; + + async function worker(): Promise { + while (idx < ids.length) { + const i = idx++; + const id = ids[i]; + display.startTask(id); + const result = await runOneDaily(modeMap.get(id)!, id, dataRoot, databaseRoot, stateRoot, display); + if (result.ok) { + display.completeTask(id, result.count ?? 0); + } else { + display.failTask(id, result.error ?? 'Unknown error'); + } + } + } + + const workers = Array.from({ length: Math.min(concurrency, ids.length) }, () => worker()); + await Promise.all(workers); + + display.stop(); +} + +/** + * Download ALL versions for a package. If enumerate didn't provide the version + * list, calls fetchPackage() to get it. Falls back to just the known version. + */ +async function downloadAllVersionsDaily( + adapter: RegistryAdapter, + indexer: Indexer, + entry: PackageEntry, +): Promise { + let versions = entry.versions; + + if (!versions?.length) { + if (entry.version) { + try { + const full = await adapter.fetchPackage(indexer, entry.name, entry.scope); + versions = full.versions; + } catch { + // Fall back to single version + } + } + if (!versions?.length && entry.version) { + versions = [entry.version]; + } + } + + if (!versions?.length) return; + + for (const v of versions) { + try { + await adapter.downloadVersion(indexer, entry.name, v, entry.scope); + } catch { + // Non-fatal + } + } +} diff --git a/@ether/library/mirror/src/resolve-registry.ts b/@ether/library/mirror/src/resolve-registry.ts new file mode 100644 index 00000000..2c149e3e --- /dev/null +++ b/@ether/library/mirror/src/resolve-registry.ts @@ -0,0 +1,10 @@ +import { LANGUAGE_TO_REGISTRY } from './core/registry-map.js'; + +const names = process.argv.slice(2); +for (const n of names) { + if (LANGUAGE_TO_REGISTRY[n]) { + console.log(LANGUAGE_TO_REGISTRY[n]); + process.exit(0); + } +} +process.exit(1); diff --git a/@ether/library/mirror/tsconfig.json b/@ether/library/mirror/tsconfig.json new file mode 100644 index 00000000..81997855 --- /dev/null +++ b/@ether/library/mirror/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true, + "outDir": "dist", + "rootDir": "src", + "declaration": true, + "sourceMap": true, + "resolveJsonModule": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/@ether/projects/library/phases/Project Index.md b/@ether/projects/library/phases/Project Index.md index 34e191ec..54b36e54 100644 --- a/@ether/projects/library/phases/Project Index.md +++ b/@ether/projects/library/phases/Project Index.md @@ -206,6 +206,8 @@ Also relevant for [[PENDING Project - Computer Networking, Security, Encryption +- 3D Graphs: GLTF, OBJ, FBX + - [[Liubov Tupikina]]'s projects ([GitHub](https://github.com/Liyubov?tab=repositories)) - Followed projects/people on other platforms (& some distance/filter away as preference) - **GitHub topics**: [interaction-design](https://github.com/topics/interaction-design), [procedural-generation](https://github.com/topics/procedural-generation), [probabilistic-programming](https://github.com/topics/probabilistic-programming), [awesome](https://github.com/topics/awesome) ([awesome-knowledge-graph](https://github.com/totogo/awesome-knowledge-graph)), [cellular-automata](https://github.com/topics/cellular-automata), [computational-design](https://github.com/topics/computational-design), [awesome-applied-category-theory](https://github.com/jules-hedges/awesome-applied-category-theory), [visualization](https://github.com/topics/visualization), [graph-rewriting](https://github.com/topics/graph-rewriting), [differentiable-rendering](https://github.com/topics/differentiable-rendering), [gamedev](https://github.com/topics/gamedev), [interaction-design](https://github.com/topics/interaction-design), diff --git a/completions/ether.bash b/completions/ether.bash new file mode 100644 index 00000000..48788aa6 --- /dev/null +++ b/completions/ether.bash @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# Tab completion for ether/ray CLI + +_ether_completions() { + local cur prev words cword + _init_completion || return + + local script_dir + script_dir="$(cd "$(dirname "$(readlink -f "$(command -v "${words[0]}" 2>/dev/null || echo "${words[0]}")")")" 2>/dev/null && pwd)" + if [[ -z "$script_dir" ]]; then + # Fallback: try to find the script relative to common locations + for d in "$HOME/Documents/github.com/orbitmines/ray" "$(pwd)"; do + if [[ -f "$d/ether" ]]; then + script_dir="$d" + break + fi + done + fi + + local cache_file="$script_dir/.ether/cache/index.tsv" + local index_file="$script_dir/Ether/library/Index.ray" + + # Helper: get language names from cache + _ether_lang_names() { + if [[ -f "$cache_file" ]]; then + awk -F'\t' '{ print $7 }' "$cache_file" 2>/dev/null | sort -u + fi + } + + # First argument completion + if [[ $cword -eq 1 ]]; then + # Completing the first word + if [[ "$cur" == Language.* ]]; then + # Complete language names after "Language." + local prefix="${cur#Language.}" + local names + names=$(_ether_lang_names) + local completions=() + while IFS= read -r name; do + if [[ -z "$prefix" ]] || [[ "${name,,}" == "${prefix,,}"* ]]; then + completions+=("Language.$name") + fi + done <<< "$names" + COMPREPLY=($(compgen -W "${completions[*]}" -- "$cur")) + elif [[ "$cur" == Lang* ]]; then + COMPREPLY=($(compgen -W "Language Language." -- "$cur")) + elif [[ "$cur" == Tool* ]]; then + COMPREPLY=($(compgen -W "Tool" -- "$cur")) + elif [[ "$cur" == Lib* ]]; then + COMPREPLY=($(compgen -W "Library" -- "$cur")) + else + COMPREPLY=($(compgen -W "Language Language. Tool Library list help" -- "$cur")) + fi + return + fi + + # Second argument completion + if [[ $cword -eq 2 ]]; then + local first="${words[1]}" + if [[ "$first" =~ ^Language\..+$ ]]; then + # Actions for a specific language + COMPREPLY=($(compgen -W "install clone update info -@" -- "$cur")) + elif [[ "$first" == "Language" ]]; then + COMPREPLY=($(compgen -W "list install clone update" -- "$cur")) + elif [[ "$first" == "Tool" || "$first" == "Library" ]]; then + COMPREPLY=($(compgen -W "list" -- "$cur")) + fi + return + fi + + # Third argument completion + if [[ $cword -eq 3 ]]; then + local first="${words[1]}" + local second="${words[2]}" + if [[ "$first" =~ ^Language\..+$ ]]; then + if [[ "$second" == "-@" ]]; then + # File/directory completion + _filedir + return + elif [[ "$second" == "install" ]]; then + COMPREPLY=($(compgen -W "--from-source" -- "$cur")) + return + fi + elif [[ "$first" == "Language" && "$second" == "install" ]]; then + COMPREPLY=($(compgen -W "--from-source" -- "$cur")) + return + fi + fi +} + +# Register completions for both ether and ray +complete -F _ether_completions ether +complete -F _ether_completions ray diff --git a/ether b/ether new file mode 100755 index 00000000..8a85e5b6 --- /dev/null +++ b/ether @@ -0,0 +1,946 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ============================================================================== +# ether - CLI tool for managing programming languages, tools, and libraries +# Aliased as: ray (via symlink) +# ============================================================================== + +# Section 1: Config & Paths +# ============================================================================== +SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" +INDEX_RAY="$SCRIPT_DIR/Ether/library/Index.ray" +LANG_SCRIPTS_DIR="$SCRIPT_DIR/Ether/library/Language" +EXTERNAL_DIR="$SCRIPT_DIR/.ether/external" +CACHE_DIR="$SCRIPT_DIR/.ether/cache" +CACHE_FILE="$CACHE_DIR/index.tsv" + +# Section 2: Index.ray Parser +# ============================================================================== + +# Parse Index.ray into a TSV cache file. +# Format: namealiasescategoryextensionsurlsgithub_urldir_name +# dir_name is the first bare identifier (e.g. CSharp not C#, FStar not F*) +parse_index_ray() { + mkdir -p "$CACHE_DIR" + awk ' + /^[[:space:]]*namespace / { + # Skip lines that are sub-namespaces (indented more than 2 spaces after the Language block) + # We want top-level namespace entries under Language + line = $0 + # Remove leading whitespace for analysis + stripped = line + gsub(/^[[:space:]]+/, "", stripped) + + # Must start with "namespace" + if (stripped !~ /^namespace /) next + + # Count leading spaces to determine nesting + match(line, /^[[:space:]]+/) + indent = RLENGTH + if (indent < 0) indent = 0 + + # We only want entries at indent level 2 (direct children of Language block) + if (indent != 2) next + + # Extract everything after "namespace " + rest = stripped + sub(/^namespace /, "", rest) + + # Extract the first identifier (dir_name) - the bare word before any | or < or ; or " + dir_name = rest + # Handle names that start with a quote + if (dir_name ~ /^"/) { + # Skip quoted-first entries, use the bare identifier + # e.g. namespace "set.mm" -> skip + next + } + # Handle F* | FStar pattern - first bare word + sub(/[[:space:]|<;(].*/, "", dir_name) + # Clean any remaining special chars + gsub(/[^a-zA-Z0-9_.]/, "", dir_name) + if (dir_name == "" || dir_name ~ /^[0-9]/) next + # If dir_name is too short (e.g. "F" from "F*"), try to find a better alias + if (length(dir_name) <= 1 && rest ~ /\|/) { + tmp2 = rest + sub(/[<;].*/, "", tmp2) + n2 = split(tmp2, aparts, /[[:space:]]*\|[[:space:]]*/) + for (j = 2; j <= n2; j++) { + candidate = aparts[j] + gsub(/"/, "", candidate) + gsub(/^[[:space:]]+|[[:space:]]+$/, "", candidate) + gsub(/[^a-zA-Z0-9_]/, "", candidate) + if (length(candidate) > 1 && candidate !~ /^[0-9]/) { + dir_name = candidate + break + } + } + } + + # Extract name (may include special chars like C#, F*) + name = rest + sub(/[[:space:]]*[|<;].*/, "", name) + sub(/[[:space:]]+$/, "", name) + # Remove quotes if present + gsub(/"/, "", name) + if (name == "") name = dir_name + + # Extract aliases (after |) + aliases = "" + if (rest ~ /\|/) { + tmp = rest + # Get all parts separated by |, before < or ; + sub(/[<;].*/, "", tmp) + n = split(tmp, parts, /[[:space:]]*\|[[:space:]]*/) + for (i = 2; i <= n; i++) { + a = parts[i] + gsub(/"/, "", a) + gsub(/^[[:space:]]+|[[:space:]]+$/, "", a) + if (a != "" && a !~ /^[[:space:]]*$/) { + if (aliases != "") aliases = aliases "," + aliases = aliases a + } + } + } + + # Extract category (Language, Tool, Library) from < Type or < Type(...) + category = "Language" + if (rest ~ /<[[:space:]]*(Tool|Library)/) { + if (rest ~ /<[[:space:]]*Tool/) category = "Tool" + else if (rest ~ /<[[:space:]]*Library/) category = "Library" + } + + # Extract extensions from Language("...") + extensions = "" + if (rest ~ /Language[[:space:]]*\(/) { + tmp = rest + sub(/.*Language[[:space:]]*\(/, "", tmp) + sub(/\).*/, "", tmp) + gsub(/"/, "", tmp) + gsub(/[[:space:]]*\|[[:space:]]*/, ",", tmp) + extensions = tmp + } + + # Extract URLs from location &= "..." + urls = "" + github_url = "" + if (rest ~ /location[[:space:]]*&=/) { + tmp = rest + sub(/.*location[[:space:]]*&=[[:space:]]*/, "", tmp) + n = split(tmp, url_parts, /[[:space:]]*&[[:space:]]*/) + for (i = 1; i <= n; i++) { + u = url_parts[i] + gsub(/"/, "", u) + gsub(/^[[:space:]]+|[[:space:]]+$/, "", u) + # Handle @"..." syntax + gsub(/@/, "", u) + if (u == "" || u !~ /^https?:\/\//) continue + if (urls != "") urls = urls "," + urls = urls u + if (u ~ /github\.com\/[^\/]+\/[^\/]+/ && github_url == "") { + # Validate it looks like a repo URL (not /topics/ or org-level) + if (u !~ /\/topics\// && u ~ /github\.com\/[^\/]+\/[^\/]+/) { + github_url = u + } + } + if (u ~ /gitlab\.com\/[^\/]+\/[^\/]+/ && github_url == "") { + github_url = u + } + } + } + + # Print TSV line + printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", name, aliases, category, extensions, urls, github_url, dir_name + } + ' "$INDEX_RAY" | awk -F'\t' '!seen[$7]++ { print }' > "$CACHE_FILE" +} + +# Ensure cache is up to date (compare mtime of Index.ray vs cache) +ensure_cache() { + if [[ ! -f "$CACHE_FILE" ]]; then + parse_index_ray + return + fi + local index_mtime cache_mtime + index_mtime=$(stat -c %Y "$INDEX_RAY" 2>/dev/null || stat -f %m "$INDEX_RAY" 2>/dev/null) + cache_mtime=$(stat -c %Y "$CACHE_FILE" 2>/dev/null || stat -f %m "$CACHE_FILE" 2>/dev/null) + if [[ "$index_mtime" -gt "$cache_mtime" ]]; then + parse_index_ray + fi +} + +# Lookup a language by name or alias. Returns the TSV line. +lookup_entry() { + local query="$1" + ensure_cache + # Try exact match on name (field 1) or dir_name (field 7) + local result + result=$(awk -F'\t' -v q="$query" ' + tolower($1) == tolower(q) || tolower($7) == tolower(q) { print; exit } + ' "$CACHE_FILE") + if [[ -n "$result" ]]; then + echo "$result" + return 0 + fi + # Try alias match (field 2, comma-separated) + result=$(awk -F'\t' -v q="$query" ' + { + n = split($2, aliases, ",") + for (i = 1; i <= n; i++) { + a = aliases[i] + gsub(/^[[:space:]]+|[[:space:]]+$/, "", a) + if (tolower(a) == tolower(q)) { print; exit } + } + } + ' "$CACHE_FILE") + if [[ -n "$result" ]]; then + echo "$result" + return 0 + fi + return 1 +} + +# Get all language names from cache +list_all_names() { + ensure_cache + awk -F'\t' '{ print $7 }' "$CACHE_FILE" | sort +} + +# Get all names for a given category +list_by_category() { + local category="$1" + ensure_cache + awk -F'\t' -v cat="$category" '$3 == cat { print $7 }' "$CACHE_FILE" | sort +} + +# Parse a TSV line into variables +# Usage: parse_entry "$line" +# Sets: ENTRY_NAME, ENTRY_ALIASES, ENTRY_CATEGORY, ENTRY_EXTENSIONS, ENTRY_URLS, ENTRY_GITHUB_URL, ENTRY_DIR_NAME +# Note: we use awk to split because bash IFS read collapses consecutive delimiters +parse_entry() { + local line="$1" + ENTRY_NAME=$(echo "$line" | awk -F'\t' '{print $1}') + ENTRY_ALIASES=$(echo "$line" | awk -F'\t' '{print $2}') + ENTRY_CATEGORY=$(echo "$line" | awk -F'\t' '{print $3}') + ENTRY_EXTENSIONS=$(echo "$line" | awk -F'\t' '{print $4}') + ENTRY_URLS=$(echo "$line" | awk -F'\t' '{print $5}') + ENTRY_GITHUB_URL=$(echo "$line" | awk -F'\t' '{print $6}') + ENTRY_DIR_NAME=$(echo "$line" | awk -F'\t' '{print $7}') +} + +# Section 3: Command Implementations +# ============================================================================== + +cmd_list() { + local category="${1:-}" + ensure_cache + if [[ -z "$category" ]]; then + echo "Languages:" + list_by_category "Language" | while read -r name; do echo " $name"; done + echo "" + echo "Tools:" + list_by_category "Tool" | while read -r name; do echo " $name"; done + echo "" + echo "Libraries:" + list_by_category "Library" | while read -r name; do echo " $name"; done + else + list_by_category "$category" | while read -r name; do echo " $name"; done + fi +} + +cmd_info() { + local lang_name="$1" + local entry + if ! entry=$(lookup_entry "$lang_name"); then + echo "Error: Unknown language '$lang_name'" >&2 + return 1 + fi + parse_entry "$entry" + echo "Name: $ENTRY_NAME" + [[ -n "$ENTRY_ALIASES" ]] && echo "Aliases: $ENTRY_ALIASES" + echo "Category: $ENTRY_CATEGORY" + [[ -n "$ENTRY_EXTENSIONS" ]] && echo "Extensions: $ENTRY_EXTENSIONS" + [[ -n "$ENTRY_URLS" ]] && echo "URLs: $(echo "$ENTRY_URLS" | tr ',' '\n' | sed 's/^/ /' | sed '1s/^ //')" + [[ -n "$ENTRY_GITHUB_URL" ]] && echo "GitHub: $ENTRY_GITHUB_URL" + echo "Dir: $ENTRY_DIR_NAME" + + local script_dir="$LANG_SCRIPTS_DIR/$ENTRY_DIR_NAME" + if [[ -d "$script_dir" ]]; then + echo "Scripts: $(ls "$script_dir"/ 2>/dev/null | tr '\n' ' ')" + # Check if installed + if [[ -f "$script_dir/check.sh" ]]; then + if bash "$script_dir/check.sh" >/dev/null 2>&1; then + echo "Installed: yes" + else + echo "Installed: no" + fi + fi + fi +} + +cmd_check_installed() { + local lang_name="$1" + local entry + if ! entry=$(lookup_entry "$lang_name"); then + echo "Error: Unknown language '$lang_name'" >&2 + return 1 + fi + parse_entry "$entry" + local check_script="$LANG_SCRIPTS_DIR/$ENTRY_DIR_NAME/check.sh" + if [[ ! -f "$check_script" ]]; then + return 1 + fi + bash "$check_script" >/dev/null 2>&1 +} + +cmd_install() { + local lang_name="$1" + local from_source="${2:-false}" + local entry + if ! entry=$(lookup_entry "$lang_name"); then + echo "Error: Unknown language '$lang_name'" >&2 + return 1 + fi + parse_entry "$entry" + local install_script="$LANG_SCRIPTS_DIR/$ENTRY_DIR_NAME/install.sh" + if [[ ! -f "$install_script" ]]; then + echo "No install script found for $ENTRY_NAME." + echo "Run 'ether Language.$ENTRY_DIR_NAME update' to generate one." + return 1 + fi + # Skip if already installed (unless --from-source requested) + if [[ "$from_source" != "true" ]]; then + local check_script="$LANG_SCRIPTS_DIR/$ENTRY_DIR_NAME/check.sh" + if [[ -f "$check_script" ]] && bash "$check_script" >/dev/null 2>&1; then + echo "$ENTRY_NAME is already installed." + return 0 + fi + fi + echo "Installing $ENTRY_NAME..." + FROM_SOURCE="$from_source" ETHER_EXTERNAL_DIR="$EXTERNAL_DIR" bash "$install_script" + echo "Done." +} + +cmd_clone() { + local lang_name="$1" + local entry + if ! entry=$(lookup_entry "$lang_name"); then + echo "Error: Unknown language '$lang_name'" >&2 + return 1 + fi + parse_entry "$entry" + + if [[ -z "$ENTRY_URLS" ]]; then + echo "No URLs found for $ENTRY_NAME." + return 1 + fi + + local cloned=0 + IFS=',' read -ra url_list <<< "$ENTRY_URLS" + for url in "${url_list[@]}"; do + url=$(echo "$url" | xargs) # trim whitespace + # Only clone github.com and gitlab.com repo URLs + if [[ "$url" =~ ^https://(github\.com|gitlab\.com)/([^/]+)/([^/]+)(/.*)?$ ]]; then + local site="${BASH_REMATCH[1]}" + local owner="${BASH_REMATCH[2]}" + local repo="${BASH_REMATCH[3]}" + # Skip non-repo URLs (topics, org-level pages without repo) + [[ "$url" =~ /topics/ ]] && continue + # Clean repo name (remove trailing slashes, .git etc) + repo="${repo%.git}" + repo="${repo%/}" + [[ -z "$repo" ]] && continue + + local target_dir="$EXTERNAL_DIR/$site/$owner/$repo" + if [[ -d "$target_dir/.git" ]]; then + echo "Updating $site/$owner/$repo..." + GIT_TERMINAL_PROMPT=0 git -C "$target_dir" pull --ff-only 2>/dev/null || GIT_TERMINAL_PROMPT=0 git -C "$target_dir" pull || true + else + echo "Cloning $url..." + mkdir -p "$(dirname "$target_dir")" + GIT_TERMINAL_PROMPT=0 git clone "$url" "$target_dir" || echo " Failed to clone $url" + fi + cloned=$((cloned + 1)) + fi + done + + if [[ $cloned -eq 0 ]]; then + echo "No cloneable repositories found for $ENTRY_NAME." + echo "URLs: $ENTRY_URLS" + fi +} + +cmd_run() { + local lang_name="$1" + local target="$2" + local entry + if ! entry=$(lookup_entry "$lang_name"); then + echo "Error: Unknown language '$lang_name'" >&2 + return 1 + fi + parse_entry "$entry" + + # Auto-install if needed + if ! cmd_check_installed "$lang_name" 2>/dev/null; then + echo "$ENTRY_NAME is not installed. Installing..." + cmd_install "$lang_name" "false" || return 1 + fi + + local run_script="$LANG_SCRIPTS_DIR/$ENTRY_DIR_NAME/run.sh" + if [[ ! -f "$run_script" ]]; then + echo "No run script found for $ENTRY_NAME." + echo "Run 'ether Language.$ENTRY_DIR_NAME update' to generate one." + return 1 + fi + bash "$run_script" "$target" +} + +cmd_repl() { + local lang_name="$1" + local entry + if ! entry=$(lookup_entry "$lang_name"); then + echo "Error: Unknown language '$lang_name'" >&2 + return 1 + fi + parse_entry "$entry" + + # Auto-install if needed + if ! cmd_check_installed "$lang_name" 2>/dev/null; then + echo "$ENTRY_NAME is not installed. Installing..." + cmd_install "$lang_name" "false" || return 1 + fi + + local repl_script="$LANG_SCRIPTS_DIR/$ENTRY_DIR_NAME/repl.sh" + if [[ ! -f "$repl_script" ]]; then + echo "$ENTRY_NAME does not have a REPL/interpreter configured." + echo "Run 'ether Language.$ENTRY_DIR_NAME update' to generate one." + return 1 + fi + exec bash "$repl_script" +} + +cmd_packages() { + local lang_name="$1" + shift + local entry + if ! entry=$(lookup_entry "$lang_name"); then + echo "Error: Unknown language '$lang_name'" >&2 + return 1 + fi + parse_entry "$entry" + + local packages_script="$LANG_SCRIPTS_DIR/$ENTRY_DIR_NAME/packages.sh" + if [[ ! -f "$packages_script" ]]; then + echo "No packages script found for $ENTRY_NAME." + echo "Run 'ether Language.$ENTRY_DIR_NAME update' to generate one." + return 1 + fi + bash "$packages_script" "$@" +} + +cmd_update() { + local lang_name="$1" + local entry + + # Phase 1: Version update (pull repos, update packages) + if entry=$(lookup_entry "$lang_name" 2>/dev/null); then + parse_entry "$entry" + echo "=== Updating $ENTRY_NAME ===" + + # Pull cloned repos + if [[ -n "$ENTRY_URLS" ]]; then + IFS=',' read -ra url_list <<< "$ENTRY_URLS" + for url in "${url_list[@]}"; do + url=$(echo "$url" | xargs) + if [[ "$url" =~ ^https://(github\.com|gitlab\.com)/([^/]+)/([^/]+)(/.*)?$ ]]; then + local site="${BASH_REMATCH[1]}" + local owner="${BASH_REMATCH[2]}" + local repo="${BASH_REMATCH[3]}" + [[ "$url" =~ /topics/ ]] && continue + repo="${repo%.git}" + repo="${repo%/}" + [[ -z "$repo" ]] && continue + local target_dir="$EXTERNAL_DIR/$site/$owner/$repo" + if [[ -d "$target_dir/.git" ]]; then + echo "Pulling latest for $site/$owner/$repo..." + GIT_TERMINAL_PROMPT=0 git -C "$target_dir" pull --ff-only 2>/dev/null || GIT_TERMINAL_PROMPT=0 git -C "$target_dir" pull || true + fi + fi + done + fi + + # Phase 2: Open Claude session for updating scripts + echo "" + echo "Opening Claude session to update $ENTRY_NAME scripts..." + local script_dir="$LANG_SCRIPTS_DIR/$ENTRY_DIR_NAME" + mkdir -p "$script_dir" + + local context="Update the language configuration for $ENTRY_NAME. +Directory: $script_dir +Category: $ENTRY_CATEGORY +Extensions: $ENTRY_EXTENSIONS +URLs: $ENTRY_URLS +GitHub: $ENTRY_GITHUB_URL + +Please review and update the install.sh, check.sh, run.sh, and repl.sh scripts in $script_dir. +Ensure they follow the project conventions (detect OS, use package managers, support FROM_SOURCE=true for install)." + + if command -v claude >/dev/null 2>&1; then + echo "$context" | claude + else + echo "Claude CLI not found. Install it to use the update command." + echo "" + echo "Context for manual update:" + echo "$context" + fi + else + # Unknown language - open Claude to search and add it + echo "Language '$lang_name' not found in Index.ray." + echo "Opening Claude session to search and add it..." + local context="The language '$lang_name' is not in $INDEX_RAY. +Please search for information about this language/tool and add an appropriate namespace entry to $INDEX_RAY. +Then create install.sh, check.sh, run.sh, and repl.sh scripts in $LANG_SCRIPTS_DIR/$lang_name/." + + if command -v claude >/dev/null 2>&1; then + echo "$context" | claude + else + echo "Claude CLI not found. Install it to use the update command." + echo "" + echo "Context for manual update:" + echo "$context" + fi + fi +} + +cmd_update_all() { + echo "=== Updating all languages ===" + ensure_cache + + # Pull all cloned repos + if [[ -d "$EXTERNAL_DIR" ]]; then + while IFS= read -r -d '' gitdir; do + local repo_dir + repo_dir=$(dirname "$gitdir") + echo "Pulling $(basename "$(dirname "$repo_dir")")/$(basename "$repo_dir")..." + GIT_TERMINAL_PROMPT=0 git -C "$repo_dir" pull --ff-only 2>/dev/null || GIT_TERMINAL_PROMPT=0 git -C "$repo_dir" pull || true + done < <(find "$EXTERNAL_DIR" -name .git -type d -print0 2>/dev/null) + fi + + # Open Claude session for all + echo "" + echo "Opening Claude session for bulk update..." + local context="Bulk update of all language configurations. +Index file: $INDEX_RAY +Language scripts directory: $LANG_SCRIPTS_DIR +Please review all languages and update their install/check/run/repl scripts." + + if command -v claude >/dev/null 2>&1; then + echo "$context" | claude + else + echo "Claude CLI not found. Install it to use the update command." + echo "" + echo "Context for manual update:" + echo "$context" + fi +} + +cmd_clone_all() { + echo "=== Cloning all repositories ===" + ensure_cache + while IFS= read -r line; do + local github_url dir_name + github_url=$(echo "$line" | awk -F'\t' '{print $6}') + dir_name=$(echo "$line" | awk -F'\t' '{print $7}') + local name + name=$(echo "$line" | awk -F'\t' '{print $1}') + if [[ -n "$github_url" ]]; then + echo "--- $name ---" + cmd_clone "$dir_name" 2>/dev/null || true + fi + done < "$CACHE_FILE" +} + +cmd_install_all() { + echo "=== Installing all languages ===" + ensure_cache + local from_source="${1:-false}" + while IFS= read -r line; do + local dir_name + dir_name=$(echo "$line" | awk -F'\t' '{print $7}') + local install_script="$LANG_SCRIPTS_DIR/$dir_name/install.sh" + if [[ -f "$install_script" ]]; then + cmd_install "$dir_name" "$from_source" || true + fi + done < "$CACHE_FILE" +} + +# Section 4: Usage & Help +# ============================================================================== + +usage() { + local prog + prog=$(basename "$0") + cat < [options] + +Commands: + Language. Enter REPL/interpreter (auto-installs) + Language. install [--from-source] Install a language + Language. clone Clone repository(ies) to .ether/external/ + Language. -@ Run a program (auto-installs) + Language. update Update version + Claude: update scripts + Language. info Show language information + Language. packages [search|info|install] Query package registry + Language.[%VER] index Index language source code for search + Language.[%VER] search Search within a language + + Language list List all languages + Language install [--from-source] Install all languages with scripts + Language clone Clone all repositories + Language update Update all languages + Language index [--lang NAME] Index source code (all or filtered) + Language search [--lang N] Semantic code search + Language server [--port PORT] Start search API (default: 8420) + Language stats Show index statistics + Language models [--use N --for T] List/switch embedding models + + Language. mirror sync Sync registry mirror for this language + Language. mirror update Incremental update + Language. mirror fetch Fetch single package from registry + Language. mirror status Show mirror status + + Language mirror sync --all [--parallel] Sync ALL language registries + Language mirror update --all [--parallel] Incremental update all + Language mirror daily [--parallel] Daily incremental (all registries) + Language mirror all [--concurrency N] Mirror ALL registries + VCS in parallel + Language mirror status Show all registry mirror statuses + Language mirror platforms List language→registry mapping + + Database. sync Sync all repos from VCS platform + Database. clone Clone single repo (bare) + releases + Database. fetch Fetch metadata only (no clone) + Database. status Show VCS sync status + + Database sync --all [--parallel] Sync all VCS platforms + Database update --all [--parallel] Incremental update all VCS + Database daily [--parallel] Daily incremental + Database all [--concurrency N] Mirror ALL VCS + registries in parallel + Database status Show all VCS statuses + +Examples: + $prog Language.Python Enter Python REPL + $prog Language.Python install Install Python + $prog Language.Python -@ script.py Run a Python script + $prog Language.Python clone Clone Python repo + $prog Language.Python packages search requests Search PyPI for 'requests' + $prog Language list List all known languages + $prog Language search "binary search tree" Search all languages + $prog Language.Rust index Index Rust repos + $prog Language.Python%3.12.0 index Index Python at version 3.12.0 + $prog Language server Start API on port 8420 +EOF +} + +# Section 5: Command Router +# ============================================================================== + +main() { + if [[ $# -eq 0 ]]; then + usage + exit 0 + fi + + local first_arg="$1" + shift + + # Handle help + if [[ "$first_arg" == "help" || "$first_arg" == "--help" || "$first_arg" == "-h" ]]; then + usage + exit 0 + fi + + # Handle Language.* commands + if [[ "$first_arg" =~ ^Language\.(.+)$ ]]; then + local lang_spec="${BASH_REMATCH[1]}" + # Parse version from Language.Name%Version syntax + local lang_name="${lang_spec%%\%*}" + local lang_version="" + if [[ "$lang_spec" == *"%"* ]]; then + lang_version="${lang_spec#*%}" + fi + local action="${1:-repl}" + shift 2>/dev/null || true + + case "$action" in + install) + local from_source="false" + [[ "${1:-}" == "--from-source" ]] && from_source="true" + cmd_install "$lang_name" "$from_source" + ;; + clone) + cmd_clone "$lang_name" + ;; + -@) + if [[ -z "${1:-}" ]]; then + echo "Error: -@ requires a file or directory argument" >&2 + exit 1 + fi + cmd_run "$lang_name" "$1" + ;; + update) + cmd_update "$lang_name" + ;; + info) + cmd_info "$lang_name" + ;; + repl) + cmd_repl "$lang_name" + ;; + packages) + cmd_packages "$lang_name" "$@" + ;; + index) + local index_args=("index" "--lang" "$lang_name") + [[ -n "$lang_version" ]] && index_args+=("--version" "$lang_version") + index_args+=("$@") + PYTHONPATH="$SCRIPT_DIR" "$SCRIPT_DIR/ar.ray/ray.py/.venv/bin/python" -m Ether.library.Index.cli "${index_args[@]}" + ;; + search) + local search_args=("search" "$@" "--lang" "$lang_name") + [[ -n "$lang_version" ]] && search_args+=("--version" "$lang_version") + PYTHONPATH="$SCRIPT_DIR" "$SCRIPT_DIR/ar.ray/ray.py/.venv/bin/python" -m Ether.library.Index.cli "${search_args[@]}" + ;; + mirror) + # Resolve language → registry platform ID + local registry_id="" + if entry=$(lookup_entry "$lang_name" 2>/dev/null) && [[ -n "$entry" ]]; then + parse_entry "$entry" + registry_id=$(cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/resolve-registry.ts "$ENTRY_NAME" "$ENTRY_DIR_NAME" "$lang_name" 2>/dev/null || true) + else + # Fallback: try lang_name directly + registry_id=$(cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/resolve-registry.ts "$lang_name" 2>/dev/null || true) + fi + if [[ -z "$registry_id" ]]; then + echo "Error: No registry mapping found for '$lang_name'" >&2 + echo "Run 'ether Language mirror platforms' to see available mappings." >&2 + exit 1 + fi + local mirror_action="${1:-sync}" + shift 2>/dev/null || true + case "$mirror_action" in + sync) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts language-sync "$registry_id" "$@" + ;; + update) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts language-update "$registry_id" "$@" + ;; + fetch) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts language-fetch "$registry_id" "$@" + ;; + status) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts language-status "$registry_id" + ;; + *) + echo "Error: Unknown mirror action '$mirror_action'" >&2 + echo "Valid: sync, update, fetch, status" >&2 + exit 1 + ;; + esac + ;; + *) + echo "Error: Unknown action '$action'" >&2 + echo "Valid actions: install, clone, -@, update, info, packages, index, search, mirror" >&2 + exit 1 + ;; + esac + exit 0 + fi + + # Handle bare "Language" commands + if [[ "$first_arg" == "Language" ]]; then + local action="${1:-list}" + shift 2>/dev/null || true + + case "$action" in + list) + cmd_list "Language" + ;; + install) + local from_source="false" + [[ "${1:-}" == "--from-source" ]] && from_source="true" + cmd_install_all "$from_source" + ;; + clone) + cmd_clone_all + ;; + update) + cmd_update_all + ;; + index) + PYTHONPATH="$SCRIPT_DIR" "$SCRIPT_DIR/ar.ray/ray.py/.venv/bin/python" -m Ether.library.Index.cli index "$@" + ;; + search) + PYTHONPATH="$SCRIPT_DIR" "$SCRIPT_DIR/ar.ray/ray.py/.venv/bin/python" -m Ether.library.Index.cli search "$@" + ;; + server) + PYTHONPATH="$SCRIPT_DIR" "$SCRIPT_DIR/ar.ray/ray.py/.venv/bin/python" -m Ether.library.Index.cli server "$@" + ;; + stats) + PYTHONPATH="$SCRIPT_DIR" "$SCRIPT_DIR/ar.ray/ray.py/.venv/bin/python" -m Ether.library.Index.cli stats "$@" + ;; + models) + PYTHONPATH="$SCRIPT_DIR" "$SCRIPT_DIR/ar.ray/ray.py/.venv/bin/python" -m Ether.library.Index.cli models "$@" + ;; + mirror) + local mirror_action="${1:-sync}" + shift 2>/dev/null || true + case "$mirror_action" in + sync) + if [[ -n "${1:-}" && "${1:-}" != --* ]]; then + # Specific platform: language-sync + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts language-sync "$@" + else + # No positional arg or --all → sync all in parallel + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts language-sync all "$@" + fi + ;; + update) + if [[ -n "${1:-}" && "${1:-}" != --* ]]; then + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts language-update "$@" + else + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts language-update all "$@" + fi + ;; + daily) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts daily "$@" + ;; + all) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts mirror-all "$@" + ;; + status) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts language-status + ;; + platforms) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts language-platforms + ;; + *) + echo "Error: Unknown mirror action '$mirror_action'" >&2 + echo "Valid: sync, update, daily, all, status, platforms" >&2 + exit 1 + ;; + esac + ;; + *) + echo "Error: Unknown Language action '$action'" >&2 + echo "Valid actions: list, install, clone, update, index, search, server, stats, models, mirror" >&2 + exit 1 + ;; + esac + exit 0 + fi + + # Handle Database.* commands (VCS platforms) + if [[ "$first_arg" =~ ^Database\.(.+)$ ]]; then + local platform_name="${BASH_REMATCH[1]}" + local action="${1:-status}" + shift 2>/dev/null || true + + case "$action" in + sync) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts database-sync "$platform_name" "$@" + ;; + update) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts database-sync "$platform_name" "$@" + ;; + clone) + if [[ -z "${1:-}" ]]; then + echo "Usage: ether Database.$platform_name clone [--release tag]" >&2 + exit 1 + fi + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts database-clone "$platform_name" "$@" + ;; + fetch) + if [[ -z "${1:-}" ]]; then + echo "Usage: ether Database.$platform_name fetch [--release tag]" >&2 + exit 1 + fi + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts database-fetch "$platform_name" "$@" + ;; + status) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts database-status "$platform_name" + ;; + *) + echo "Error: Unknown Database action '$action'" >&2 + echo "Valid: sync, update, clone, fetch, status" >&2 + exit 1 + ;; + esac + exit 0 + fi + + # Handle bare "Database" commands + if [[ "$first_arg" == "Database" ]]; then + local action="${1:-sync}" + shift 2>/dev/null || true + + case "$action" in + sync) + if [[ -n "${1:-}" && "${1:-}" != --* ]]; then + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts database-sync "$@" + else + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts database-sync all "$@" + fi + ;; + update) + if [[ -n "${1:-}" && "${1:-}" != --* ]]; then + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts database-update "$@" + else + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts database-sync all "$@" + fi + ;; + daily) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts daily "$@" + ;; + all) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts mirror-all "$@" + ;; + status) + cd "$SCRIPT_DIR/@ether/library/mirror" && npx tsx src/cli.ts database-status + ;; + *) + echo "Error: Unknown Database action '$action'" >&2 + echo "Valid: sync, update, daily, all, status" >&2 + exit 1 + ;; + esac + exit 0 + fi + + # Handle Tool/Library + if [[ "$first_arg" == "Tool" || "$first_arg" == "Library" ]]; then + local action="${1:-list}" + case "$action" in + list) + cmd_list "$first_arg" + ;; + *) + echo "Error: Unknown $first_arg action '$action'" >&2 + echo "Valid actions: list" >&2 + exit 1 + ;; + esac + exit 0 + fi + + # Handle "list" as shorthand + if [[ "$first_arg" == "list" ]]; then + cmd_list + exit 0 + fi + + echo "Error: Unknown command '$first_arg'" >&2 + echo "Run '$(basename "$0") --help' for usage." >&2 + exit 1 +} + +main "$@" diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 index 8e97496a..153da56a --- a/install.sh +++ b/install.sh @@ -1,2 +1,81 @@ -# TODO Install Ether CLI which accepts arguments and set those to their respective external fields. -echo "TODO" \ No newline at end of file +#!/usr/bin/env bash +set -euo pipefail + +# Install the ether/ray CLI tool +# Sets up PATH and shell completions + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ETHER_BIN="$SCRIPT_DIR/ether" + +echo "=== Installing ether CLI ===" + +# Verify the ether script exists +if [[ ! -f "$ETHER_BIN" ]]; then + echo "Error: ether script not found at $ETHER_BIN" >&2 + exit 1 +fi + +# Ensure executable +chmod +x "$ETHER_BIN" + +# Create runtime directories +mkdir -p "$SCRIPT_DIR/.ether/external" +mkdir -p "$SCRIPT_DIR/.ether/cache" + +# Add to PATH via shell profile +add_to_path() { + local shell_rc="$1" + local path_line="export PATH=\"$SCRIPT_DIR:\$PATH\"" + local completion_line="[[ -f \"$SCRIPT_DIR/completions/ether.bash\" ]] && source \"$SCRIPT_DIR/completions/ether.bash\"" + + if [[ -f "$shell_rc" ]]; then + # Add PATH if not already present (check for exact export line) + if ! grep -qxF "$path_line" "$shell_rc" 2>/dev/null; then + echo "" >> "$shell_rc" + echo "# ether/ray CLI" >> "$shell_rc" + echo "$path_line" >> "$shell_rc" + echo "Added $SCRIPT_DIR to PATH in $shell_rc" + else + echo "PATH already configured in $shell_rc" + fi + + # Add bash completion if it's a bash config + if [[ "$shell_rc" == *"bashrc"* || "$shell_rc" == *"bash_profile"* ]]; then + if ! grep -qxF "$completion_line" "$shell_rc" 2>/dev/null; then + echo "$completion_line" >> "$shell_rc" + echo "Added tab completion to $shell_rc" + else + echo "Tab completion already configured in $shell_rc" + fi + fi + fi +} + +# Detect shell and configure +if [[ -n "${BASH_VERSION:-}" ]] || [[ "$SHELL" == *bash* ]]; then + if [[ "$(uname)" == "Darwin" ]]; then + add_to_path "$HOME/.bash_profile" + else + add_to_path "$HOME/.bashrc" + fi +fi + +if [[ "$SHELL" == *zsh* ]] || [[ -f "$HOME/.zshrc" ]]; then + add_to_path "$HOME/.zshrc" +fi + +# Parse the Index.ray to build initial cache +echo "Building Index.ray cache..." +"$ETHER_BIN" Language list >/dev/null 2>&1 && echo "Cache built successfully." || echo "Warning: Cache build had issues (this is OK on first run)." + +echo "" +echo "=== Installation complete ===" +echo "" +echo "Restart your shell or run:" +echo " export PATH=\"$SCRIPT_DIR:\$PATH\"" +echo " source $SCRIPT_DIR/completions/ether.bash" +echo "" +echo "Then try:" +echo " ether Language list" +echo " ether Language.Python install" +echo " ray Language.Python" diff --git a/ray b/ray new file mode 120000 index 00000000..77f2e432 --- /dev/null +++ b/ray @@ -0,0 +1 @@ +ether \ No newline at end of file