From 0d51c3541dd03e28f24d0104bcacdae9e389eb11 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sun, 26 Jul 2026 21:12:20 -0400 Subject: [PATCH] fix(twitter_threads): strip trailing slashes from --media-dir and --output Path objects with trailing separators (e.g. './media/') intermittently failed to glob on Windows after download_media.py had just finished writing the directory. Normalize via rstrip('/\\\\') before Path() re-wrapping so the CLI is forgiving regardless of OS path quirks. Repro: gallery-dl ran + immediate render with trailing slash on the just-created media/ dir -> glob returned nothing -> markdown emitted no ![Media N] lines. Removing the trailing slash fixed it; this makes both work. --- .opencode/package-lock.json | 400 +++++++++++++++++- .../media/2063642010649530377_1.png | Bin 0 -> 965 bytes .../media/2063642851284529466_1.png | Bin 0 -> 1662 bytes .../media/2063643677440831673_1.png | Bin 0 -> 917 bytes .../media/2063643677440831673_2.png | Bin 0 -> 751 bytes .../media/2063643677440831673_3.png | Bin 0 -> 3807 bytes docs/twitter/2063733456144597200/thread.md | 77 ++++ .../2063733456144597200/thread_data.json | 206 +++++++++ manualslop_layout.ini | 132 ++++++ scripts/twitter_threads/download_media.py | 2 + scripts/twitter_threads/render_markdown.py | 2 + tests/test_twitter_threads_pipeline.py | 28 ++ 12 files changed, 846 insertions(+), 1 deletion(-) create mode 100644 docs/twitter/2063733456144597200/media/2063642010649530377_1.png create mode 100644 docs/twitter/2063733456144597200/media/2063642851284529466_1.png create mode 100644 docs/twitter/2063733456144597200/media/2063643677440831673_1.png create mode 100644 docs/twitter/2063733456144597200/media/2063643677440831673_2.png create mode 100644 docs/twitter/2063733456144597200/media/2063643677440831673_3.png create mode 100644 docs/twitter/2063733456144597200/thread.md create mode 100644 docs/twitter/2063733456144597200/thread_data.json create mode 100644 manualslop_layout.ini diff --git a/.opencode/package-lock.json b/.opencode/package-lock.json index 69798984..8d6c18f3 100644 --- a/.opencode/package-lock.json +++ b/.opencode/package-lock.json @@ -1 +1,399 @@ -{ "name": ".opencode", "lockfileVersion": 3, "requires": true, "packages": { "": { "dependencies": { "@opencode-ai/plugin": "1.17.8" } }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.4.tgz", "integrity": "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==", "cpu": [ "arm64" ], "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.4.tgz", "integrity": "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==", "cpu": [ "x64" ], "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.4.tgz", "integrity": "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==", "cpu": [ "arm" ], "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.4.tgz", "integrity": "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==", "cpu": [ "arm64" ], "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.4.tgz", "integrity": "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==", "cpu": [ "x64" ], "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.4.tgz", "integrity": "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==", "cpu": [ "x64" ], "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@opencode-ai/plugin": { "version": "1.17.8", "resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.17.8.tgz", "integrity": "sha512-pkmnYQz5d+xf0h6fAjgplSSJKLqgYKOXr+x6y40GRPdW+/IfndFkMGq7CDsG2SieGD84qv4zYDMyolGo06IMpw==", "license": "MIT", "dependencies": { "@opencode-ai/sdk": "1.17.8", "effect": "4.0.0-beta.74", "zod": "4.1.8" }, "peerDependencies": { "@opentui/core": ">=0.3.4", "@opentui/keymap": ">=0.3.4", "@opentui/solid": ">=0.3.4" }, "peerDependenciesMeta": { "@opentui/core": { "optional": true }, "@opentui/keymap": { "optional": true }, "@opentui/solid": { "optional": true } } }, "node_modules/@opencode-ai/sdk": { "version": "1.17.8", "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.17.8.tgz", "integrity": "sha512-6MKmsj2ujZyL44jy+12dpwWYDYKPS9fUr+0wVQxaIlPYQ/eAt8T8T3QrybplJ5ZtHfZUX+esXZ02x2UYYm7oEw==", "license": "MIT", "dependencies": { "cross-spawn": "7.0.6" } }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" }, "engines": { "node": ">= 8" } }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "license": "Apache-2.0", "optional": true, "engines": { "node": ">=8" } }, "node_modules/effect": { "version": "4.0.0-beta.74", "resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-beta.74.tgz", "integrity": "sha512-Yx+Kh12U+i2FmjwEfKs+ePFmpMd43RPD1oGqc/VraSS9bYzvF0Ff3PojwEFEVEewp8xc92Uxu28gTspU4qyvHA==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.8.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.1", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^14.0.0", "yaml": "^2.9.0" } }, "node_modules/fast-check": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.8.0.tgz", "integrity": "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/dubzzz" }, { "type": "opencollective", "url": "https://opencollective.com/fast-check" } ], "license": "MIT", "dependencies": { "pure-rand": "^8.0.0" }, "engines": { "node": ">=12.17.0" } }, "node_modules/find-my-way-ts": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz", "integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==", "license": "MIT" }, "node_modules/ini": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/ini/-/ini-7.0.0.tgz", "integrity": "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w==", "license": "ISC", "engines": { "node": "^22.22.2 || ^24.15.0 || >=26.0.0" } }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/kubernetes-types": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/kubernetes-types/-/kubernetes-types-1.30.0.tgz", "integrity": "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==", "license": "Apache-2.0" }, "node_modules/msgpackr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-2.0.4.tgz", "integrity": "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA==", "license": "MIT", "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "node_modules/msgpackr-extract": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.4.tgz", "integrity": "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==", "hasInstallScript": true, "license": "MIT", "optional": true, "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" } }, "node_modules/multipasta": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/multipasta/-/multipasta-0.2.7.tgz", "integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==", "license": "MIT" }, "node_modules/node-gyp-build-optional-packages": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", "license": "MIT", "optional": true, "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/pure-rand": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.0.tgz", "integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/dubzzz" }, { "type": "opencollective", "url": "https://opencollective.com/fast-check" } ], "license": "MIT" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/toml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/toml/-/toml-4.1.1.tgz", "integrity": "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==", "license": "MIT", "engines": { "node": ">=20" } }, "node_modules/uuid": { "version": "14.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz", "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "license": "MIT", "bin": { "uuid": "dist-node/bin/uuid" } }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" }, "engines": { "node": ">= 8" } }, "node_modules/yaml": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14.6" }, "funding": { "url": "https://github.com/sponsors/eemeli" } }, "node_modules/zod": { "version": "4.1.8", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } } }} \ No newline at end of file +{ + "name": ".opencode", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@opencode-ai/plugin": "1.17.13" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.8.tgz", + "integrity": "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.4.tgz", + "integrity": "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.4.tgz", + "integrity": "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.4.tgz", + "integrity": "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.4.tgz", + "integrity": "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.4.tgz", + "integrity": "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.4.tgz", + "integrity": "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@opencode-ai/plugin": { + "version": "1.17.13", + "resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.17.13.tgz", + "integrity": "sha512-JjoIs6qTPl0IrXo+J1GTqX9lcb2h2dMoW6BWMR2IbTT3MY2FQ/lvBXDzkx0d3zVRaYN+NTmV4u8Nth396xq+sQ==", + "license": "MIT", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@opencode-ai/sdk": "1.17.13", + "effect": "4.0.0-beta.83", + "zod": "4.1.8" + }, + "peerDependencies": { + "@opentui/core": ">=0.3.4", + "@opentui/keymap": ">=0.3.4", + "@opentui/solid": ">=0.3.4" + }, + "peerDependenciesMeta": { + "@opentui/core": { + "optional": true + }, + "@opentui/keymap": { + "optional": true + }, + "@opentui/solid": { + "optional": true + } + } + }, + "node_modules/@opencode-ai/sdk": { + "version": "1.17.13", + "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.17.13.tgz", + "integrity": "sha512-VItOGjMzRQx3zypwmeFLNhCiIx32kxS7FqzIJvVZLfyNGCifs3rfGC9qzNKWcxQo4SjNvAw++v4gWWU6Inv+JQ==", + "license": "MIT", + "dependencies": { + "cross-spawn": "7.0.6" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/effect": { + "version": "4.0.0-beta.83", + "resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-beta.83.tgz", + "integrity": "sha512-0wsak8RtgGAr9UWSbVDgJHZcUqMSvicHcvaZv1MbMM7MCGgW4Rn/137J1MHQbwYPcwYGxT/IqehFd+UbYuj78w==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "fast-check": "^4.8.0", + "find-my-way-ts": "^0.1.6", + "ini": "^7.0.0", + "kubernetes-types": "^1.30.0", + "msgpackr": "^2.0.1", + "multipasta": "^0.2.7", + "toml": "^4.1.1", + "uuid": "^14.0.0", + "yaml": "^2.9.0" + } + }, + "node_modules/fast-check": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.8.0.tgz", + "integrity": "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^8.0.0" + }, + "engines": { + "node": ">=12.17.0" + } + }, + "node_modules/find-my-way-ts": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz", + "integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==", + "license": "MIT" + }, + "node_modules/ini": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-7.0.0.tgz", + "integrity": "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w==", + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/kubernetes-types": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/kubernetes-types/-/kubernetes-types-1.30.0.tgz", + "integrity": "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==", + "license": "Apache-2.0" + }, + "node_modules/msgpackr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-2.0.4.tgz", + "integrity": "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA==", + "license": "MIT", + "optionalDependencies": { + "msgpackr-extract": "^3.0.4" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.4.tgz", + "integrity": "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" + } + }, + "node_modules/multipasta": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/multipasta/-/multipasta-0.2.7.tgz", + "integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==", + "license": "MIT" + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pure-rand": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.1.tgz", + "integrity": "sha512-c58R2+SPFcSIPXoU834QN/KPDDOSd8sXcSrqf6e83Me6Rrp1EYkxukkjXMVrKvKaADs1SOyNkWdfvLf6zY8qLQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/toml": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/toml/-/toml-4.1.2.tgz", + "integrity": "sha512-m0vXfHODcw3gk+KONAOlVQ5yNHc3yS3B1ybM3HS1vqDoS0RWTDDVBVVTYi8hH0k+2OM1vmo9fb1WX9EVqjqfHA==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/uuid": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz", + "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/zod": { + "version": "4.1.8", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/docs/twitter/2063733456144597200/media/2063642010649530377_1.png b/docs/twitter/2063733456144597200/media/2063642010649530377_1.png new file mode 100644 index 0000000000000000000000000000000000000000..2a76bef5f436d04a3c938b2b2633cdcc6689f446 GIT binary patch literal 965 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 MboFyt=akR{03hj44gdfE literal 0 HcmV?d00001 diff --git a/docs/twitter/2063733456144597200/media/2063643677440831673_3.png b/docs/twitter/2063733456144597200/media/2063643677440831673_3.png new file mode 100644 index 0000000000000000000000000000000000000000..bcb73670757eec5f0f79830f8e2c27d836d0f98d GIT binary patch literal 3807 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 Tz>S=Z&)C+=(UM_)`Obd;L@JgC literal 0 HcmV?d00001 diff --git a/docs/twitter/2063733456144597200/thread.md b/docs/twitter/2063733456144597200/thread.md new file mode 100644 index 00000000..f164fac1 --- /dev/null +++ b/docs/twitter/2063733456144597200/thread.md @@ -0,0 +1,77 @@ +--- +title: "@NOTimothyLottes I see!" +author: "OZ" +handle: "@winning_tactic" +post_url: "https://x.com/winning_tactic/status/2063733456144597200" +post_id: "2063733456144597200" +timestamp: "2026-06-07 21:22:52" +post_count: 12 +reply_count: 0 +repost_count: 0 +like_count: 0 +view_count: 11 +--- + +# @winning_tactic — @NOTimothyLottes I see! + +## Post 1 (2026-06-07 15:04:23) + +Error codes, many APIs get these so wrong. For example aliasing the same code with multiple meaning so the user has zero idea what actually went wrong and what needs fixing. Here is what I do -> thread + +## Post 2 (2026-06-07 15:07:23) — reply to Post 1 + +I have a force no-inline exit point which prints +ERROR[__line__]:__code__ +Where 'line' is the line number macro __LINE__ passed in from the source, and 'code' is the specific error code. This exits with error code set to 'line'. Thus easy to find termination point in source. + +## Post 3 (2026-06-07 15:13:52) — reply to Post 2 + +Function also scales 'line' by 100, and places the version in the lower digits. So know which release version (I'm not doing more than 100 post-release updates). Note all my source is in a single file (including shader source), so I don't need a file in the error print out + +## Post 4 (2026-06-07 15:19:30) — reply to Post 3 + +I use force inline macros (I_ in my code) that wrap error checks like testing if a win32 call errors with a null pointer (Err0), and uses builtin expect assuming no error to filter through another no-inline (N_) function to GetLastError and exit if fail, otherwise return pointer + +![Media 1](./media/2063642010649530377_1.png) + +## Post 5 (2026-06-07 15:21:31) — reply to Post 4 + +Which means I can simply wrap the calls to WIN32 with a specific Err function and it auto does terminal error checks for cases that shouldn't happen in practice, but if it does happen at least I get instant ability to know where and why + +## Post 6 (2026-06-07 15:22:51) — reply to Post 5 + +The defines I use for context + +![Media 1](./media/2063642851284529466_1.png) + +## Post 7 (2026-06-07 15:26:08) — reply to Post 6 + +And if this is new, what I do for imports is using a M_(name) macro which imports WIN32 symbols as "void name(void)" functions, which I typecast to the correct type at the exact point of call. Means I don't need any system headers or header like code in my code :) + +![Media 1](./media/2063643677440831673_1.png) +![Media 2](./media/2063643677440831673_2.png) +![Media 3](./media/2063643677440831673_3.png) + +## Post 8 (2026-06-07 15:28:34) — reply to Post 7 + +At least for WIN32 I do use standard in EXE dynamic linking since Windows doesn't have the Linux .SO nightmare problem. On Linux I only link to libdl and dlopen and dlsym everything else. In theory that gives portability due to ABI and common libdl naming. + +## Post 9 (2026-06-07 15:30:51) — reply to Post 8 + +The result of all this is "keeping it simple". For the most part I don't do any runtime dynamic creation of 'things' so all my error checks are init time (low cost) only and fail just results in this common Err() with printed {line,code} exit path. + +## Post 10 (2026-06-07 17:18:38) — reply to Post 9 + +Is the error centrally located? e.g. whatever GetLastErr does? I'm motivated to spend some time prettying my own usage, but I keep errors at the call sites, but do a lot of the same action, but the cost is every call is a macro to the real call that handles the rigamarole. green thread based so centrally located is a problem, even though we could do off the curr_tsk register +https://gitlab.com/qsrc.net/Lampyr/-/blob/dev/rt/file.h?ref_type=heads#L61 +then you have to do this kind of jumping through hoops because no one wants to set it up themselves. +https://gitlab.com/qsrc.net/Lampyr/-/blob/dev/rt/mem.h?ref_type=heads#L10 +You certainly have a lot of helper macros and single letter api about them, which I like. tasteful yet foreign. + +## Post 11 (2026-06-07 21:12:08) — reply to Post 10 + +@winning_tactic These are all for errors that kill the application. GetLastError is like the WIN32 version of error number from libc (figure out why an allocation that returned zero failed). + +## Post 12 (2026-06-07 21:22:52) — reply to Post 11 + +@NOTimothyLottes I see! diff --git a/docs/twitter/2063733456144597200/thread_data.json b/docs/twitter/2063733456144597200/thread_data.json new file mode 100644 index 00000000..0869f3fa --- /dev/null +++ b/docs/twitter/2063733456144597200/thread_data.json @@ -0,0 +1,206 @@ +{ + "root_post_id": "2063733456144597200", + "posts": [ + { + "post_id": "2063638204394181034", + "author": "NOTimothyLottes", + "handle": "NOTimothyLottes", + "text": "Error codes, many APIs get these so wrong. For example aliasing the same code with multiple meaning so the user has zero idea what actually went wrong and what needs fixing. Here is what I do -> thread", + "timestamp": "2026-06-07 15:04:23", + "media_urls": [], + "reply_to_id": null, + "quote_of_id": null, + "metrics": { + "reply_count": 3, + "repost_count": 4, + "like_count": 47, + "view_count": 8479 + } + }, + { + "post_id": "2063638960790737206", + "author": "NOTimothyLottes", + "handle": "NOTimothyLottes", + "text": "I have a force no-inline exit point which prints\nERROR[__line__]:__code__ \nWhere 'line' is the line number macro __LINE__ passed in from the source, and 'code' is the specific error code. This exits with error code set to 'line'. Thus easy to find termination point in source.", + "timestamp": "2026-06-07 15:07:23", + "media_urls": [], + "reply_to_id": "2063638204394181034", + "quote_of_id": null, + "metrics": { + "reply_count": 1, + "repost_count": 0, + "like_count": 12, + "view_count": 1060 + } + }, + { + "post_id": "2063640590730842264", + "author": "NOTimothyLottes", + "handle": "NOTimothyLottes", + "text": "Function also scales 'line' by 100, and places the version in the lower digits. So know which release version (I'm not doing more than 100 post-release updates). Note all my source is in a single file (including shader source), so I don't need a file in the error print out", + "timestamp": "2026-06-07 15:13:52", + "media_urls": [], + "reply_to_id": "2063638960790737206", + "quote_of_id": null, + "metrics": { + "reply_count": 1, + "repost_count": 0, + "like_count": 12, + "view_count": 987 + } + }, + { + "post_id": "2063642010649530377", + "author": "NOTimothyLottes", + "handle": "NOTimothyLottes", + "text": "I use force inline macros (I_ in my code) that wrap error checks like testing if a win32 call errors with a null pointer (Err0), and uses builtin expect assuming no error to filter through another no-inline (N_) function to GetLastError and exit if fail, otherwise return pointer", + "timestamp": "2026-06-07 15:19:30", + "media_urls": [ + "https://pbs.twimg.com/media/HKOGypaW4AEU4Xl?format=png&name=orig" + ], + "reply_to_id": "2063640590730842264", + "quote_of_id": null, + "metrics": { + "reply_count": 1, + "repost_count": 0, + "like_count": 8, + "view_count": 689 + } + }, + { + "post_id": "2063642518168739956", + "author": "NOTimothyLottes", + "handle": "NOTimothyLottes", + "text": "Which means I can simply wrap the calls to WIN32 with a specific Err function and it auto does terminal error checks for cases that shouldn't happen in practice, but if it does happen at least I get instant ability to know where and why", + "timestamp": "2026-06-07 15:21:31", + "media_urls": [], + "reply_to_id": "2063642010649530377", + "quote_of_id": null, + "metrics": { + "reply_count": 1, + "repost_count": 0, + "like_count": 6, + "view_count": 592 + } + }, + { + "post_id": "2063642851284529466", + "author": "NOTimothyLottes", + "handle": "NOTimothyLottes", + "text": "The defines I use for context", + "timestamp": "2026-06-07 15:22:51", + "media_urls": [ + "https://pbs.twimg.com/media/HKOIKxeXYAALKO_?format=png&name=orig" + ], + "reply_to_id": "2063642518168739956", + "quote_of_id": null, + "metrics": { + "reply_count": 1, + "repost_count": 0, + "like_count": 7, + "view_count": 564 + } + }, + { + "post_id": "2063643677440831673", + "author": "NOTimothyLottes", + "handle": "NOTimothyLottes", + "text": "And if this is new, what I do for imports is using a M_(name) macro which imports WIN32 symbols as \"void name(void)\" functions, which I typecast to the correct type at the exact point of call. Means I don't need any system headers or header like code in my code :)", + "timestamp": "2026-06-07 15:26:08", + "media_urls": [ + "https://pbs.twimg.com/media/HKOIsxFXgAA_z35?format=png&name=orig", + "https://pbs.twimg.com/media/HKOIx20XMAAtIoB?format=png&name=orig", + "https://pbs.twimg.com/media/HKOI3rPWEAAZ9t0?format=png&name=orig" + ], + "reply_to_id": "2063642851284529466", + "quote_of_id": null, + "metrics": { + "reply_count": 2, + "repost_count": 0, + "like_count": 8, + "view_count": 544 + } + }, + { + "post_id": "2063644292711690546", + "author": "NOTimothyLottes", + "handle": "NOTimothyLottes", + "text": "At least for WIN32 I do use standard in EXE dynamic linking since Windows doesn't have the Linux .SO nightmare problem. On Linux I only link to libdl and dlopen and dlsym everything else. In theory that gives portability due to ABI and common libdl naming.", + "timestamp": "2026-06-07 15:28:34", + "media_urls": [], + "reply_to_id": "2063643677440831673", + "quote_of_id": null, + "metrics": { + "reply_count": 1, + "repost_count": 0, + "like_count": 8, + "view_count": 790 + } + }, + { + "post_id": "2063644866127552521", + "author": "NOTimothyLottes", + "handle": "NOTimothyLottes", + "text": "The result of all this is \"keeping it simple\". For the most part I don't do any runtime dynamic creation of 'things' so all my error checks are init time (low cost) only and fail just results in this common Err() with printed {line,code} exit path.", + "timestamp": "2026-06-07 15:30:51", + "media_urls": [], + "reply_to_id": "2063644292711690546", + "quote_of_id": null, + "metrics": { + "reply_count": 1, + "repost_count": 0, + "like_count": 9, + "view_count": 747 + } + }, + { + "post_id": "2063671989991264586", + "author": "OZ", + "handle": "winning_tactic", + "text": "Is the error centrally located? e.g. whatever GetLastErr does? I'm motivated to spend some time prettying my own usage, but I keep errors at the call sites, but do a lot of the same action, but the cost is every call is a macro to the real call that handles the rigamarole. green thread based so centrally located is a problem, even though we could do off the curr_tsk register\nhttps://gitlab.com/qsrc.net/Lampyr/-/blob/dev/rt/file.h?ref_type=heads#L61\nthen you have to do this kind of jumping through hoops because no one wants to set it up themselves.\nhttps://gitlab.com/qsrc.net/Lampyr/-/blob/dev/rt/mem.h?ref_type=heads#L10\nYou certainly have a lot of helper macros and single letter api about them, which I like. tasteful yet foreign.", + "timestamp": "2026-06-07 17:18:38", + "media_urls": [], + "reply_to_id": "2063644866127552521", + "quote_of_id": null, + "metrics": { + "reply_count": 1, + "repost_count": 0, + "like_count": 0, + "view_count": 97 + } + }, + { + "post_id": "2063730754861822129", + "author": "NOTimothyLottes", + "handle": "NOTimothyLottes", + "text": "@winning_tactic These are all for errors that kill the application. GetLastError is like the WIN32 version of error number from libc (figure out why an allocation that returned zero failed).", + "timestamp": "2026-06-07 21:12:08", + "media_urls": [], + "reply_to_id": "2063671989991264586", + "quote_of_id": null, + "metrics": { + "reply_count": 1, + "repost_count": 0, + "like_count": 0, + "view_count": 28 + } + }, + { + "post_id": "2063733456144597200", + "author": "OZ", + "handle": "winning_tactic", + "text": "@NOTimothyLottes I see!", + "timestamp": "2026-06-07 21:22:52", + "media_urls": [], + "reply_to_id": "2063730754861822129", + "quote_of_id": null, + "metrics": { + "reply_count": 0, + "repost_count": 0, + "like_count": 0, + "view_count": 11 + } + } + ], + "source_url": "https://x.com/winning_tactic/status/2063733456144597200" +} \ No newline at end of file diff --git a/manualslop_layout.ini b/manualslop_layout.ini new file mode 100644 index 00000000..15cded89 --- /dev/null +++ b/manualslop_layout.ini @@ -0,0 +1,132 @@ +;;; !!! This configuration is handled by HelloImGui and stores several Ini Files, separated by markers like this: + ;;;<<>>;;; + +;;;<<>>;;; +[Window][Project Settings] +Pos=0,28 +Size=1666,1172 +Collapsed=0 +DockId=0xAFC85805,3 + +[Window][Files & Media] +Pos=0,28 +Size=1666,1172 +Collapsed=0 +DockId=0xAFC85805,4 + +[Window][AI Settings] +Pos=0,28 +Size=1666,1172 +Collapsed=0 +DockId=0xAFC85805,5 + +[Window][Operations Hub] +Pos=0,28 +Size=1666,1172 +Collapsed=0 +DockId=0xAFC85805,7 + +[Window][Theme] +Pos=0,28 +Size=1666,1172 +Collapsed=0 +DockId=0xAFC85805,6 + +[Window][Discussion Hub] +Pos=0,28 +Size=1666,1172 +Collapsed=0 +DockId=0xAFC85805,0 + +[Window][Log Management] +Pos=0,28 +Size=1666,1172 +Collapsed=0 +DockId=0xAFC85805,1 + +[Window][Diagnostics] +Pos=0,28 +Size=1666,1172 +Collapsed=0 +DockId=0xAFC85805,2 + +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Response] +Pos=346,635 +Size=794,758 +Collapsed=0 + +[Window][Project Stale] +Pos=10,50 +Size=169,184 +Collapsed=0 + +[Table][0x7804123E,3] +RefScale=20 +Column 0 Width=60 +Column 1 Weight=1.0000 +Column 2 Width=70 + +[Table][0x56EAD150,3] +RefScale=20 +Column 0 Width=60 +Column 1 Weight=1.0000 +Column 2 Width=70 + +[Table][0x87F76FD6,3] +RefScale=20 +Column 0 Width=60 +Column 1 Weight=1.0000 +Column 2 Width=70 + +[Table][0x3459F0E7,3] +RefScale=20 +Column 0 Width=60 +Column 1 Weight=1.0000 +Column 2 Width=70 + +[Table][0x51981450,3] +RefScale=20 +Column 0 Width=60 +Column 1 Weight=1.0000 +Column 2 Width=70 + +[Table][0x48E1D781,3] +RefScale=20 +Column 0 Width=60 +Column 1 Weight=1.0000 +Column 2 Width=70 + +[Table][0xFC15AE63,7] +Column 0 Weight=1.0000 +Column 1 Weight=1.0000 +Column 2 Weight=1.0000 +Column 3 Weight=1.0000 +Column 4 Weight=1.0000 +Column 5 Weight=1.0000 +Column 6 Weight=1.0000 + +[Table][0xA02D8C87,3] +RefScale=20 +Column 0 Width=150 +Column 1 Width=100 +Column 2 Weight=1.0000 + +[Docking][Data] +DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,28 Size=1666,1172 CentralNode=1 Selected=0x3F1379AF + +;;;<<>>;;; +;;;<<>>;;; +[Layout] +Name=Default +[StatusBar] +Show=false +ShowFps=true +[Theme] +Name=ImGuiColorsDark +;;;<<>>;;; +{"gImGuiSplitIDs":{"MainDockSpace":2949142533}} diff --git a/scripts/twitter_threads/download_media.py b/scripts/twitter_threads/download_media.py index da8ad40f..2023a13a 100644 --- a/scripts/twitter_threads/download_media.py +++ b/scripts/twitter_threads/download_media.py @@ -40,6 +40,8 @@ def main(argv: list[str] | None = None) -> int: parser.add_argument("--output", type=Path, required=True, help="media output directory") parser.add_argument("--cookies", type=Path, default=None, help="cookies.txt for gallery-dl auth") args = parser.parse_args(argv) + args.output = Path(str(args.output).rstrip("/\\")) + args.cookies = Path(str(args.cookies).rstrip("/\\")) if args.cookies is not None else None try: raw = args.input.read_text(encoding="utf-8") except OSError as e: diff --git a/scripts/twitter_threads/render_markdown.py b/scripts/twitter_threads/render_markdown.py index 057bc3cd..2a21b845 100644 --- a/scripts/twitter_threads/render_markdown.py +++ b/scripts/twitter_threads/render_markdown.py @@ -96,6 +96,8 @@ def main(argv: list[str] | None = None) -> int: parser.add_argument("--media-dir", type=Path, required=True, help="media directory to link") parser.add_argument("--output", type=Path, required=True, help="output .md path") args = parser.parse_args(argv) + args.media_dir = Path(str(args.media_dir).rstrip("/\\")) + args.output = Path(str(args.output).rstrip("/\\")) try: raw = args.input.read_text(encoding="utf-8") except OSError as e: diff --git a/tests/test_twitter_threads_pipeline.py b/tests/test_twitter_threads_pipeline.py index 7decb949..e9b2d2c3 100644 --- a/tests/test_twitter_threads_pipeline.py +++ b/tests/test_twitter_threads_pipeline.py @@ -99,3 +99,31 @@ def test_render_cli(tmp_path: Path) -> None: text = out.read_text(encoding="utf-8") assert "[Media 1](./media/7_img1.jpg)" in text assert "body" in text + +def test_render_cli_trailing_slash_on_media_dir(tmp_path: Path) -> None: + p1 = _post("8", text="body", media_urls=("https://pbs.twimg.com/media/DDD.jpg",)) + t = ThreadData(root_post_id="8", posts=(p1,), source_url="https://x.com/x/x/8") + thread_data_json = tmp_path / "thread_data.json" + thread_data_json.write_text(json.dumps(thread_to_dict(t)), encoding="utf-8") + mediadir = tmp_path / "media" + mediadir.mkdir() + (mediadir / "8_img1.jpg").write_bytes(b"x") + out = tmp_path / "thread.md" + code = render_main(["--input", str(thread_data_json), "--media-dir", "./" + str(mediadir).replace("\\", "/") + "/", "--output", str(out)]) + assert code == 0 + text = out.read_text(encoding="utf-8") + assert "[Media 1](./media/8_img1.jpg)" in text + assert "body" in text + +def test_download_cli_trailing_slash_on_output(tmp_path: Path) -> None: + p1 = _post("9", media_urls=("https://pbs.twimg.com/media/EEE.jpg",)) + t = ThreadData(root_post_id="9", posts=(p1,), source_url="https://x.com/x/x/9") + thread_data_json = tmp_path / "thread_data.json" + thread_data_json.write_text(json.dumps(thread_to_dict(t)), encoding="utf-8") + mediadir = tmp_path / "media" + mediadir.mkdir() + (mediadir / "9_1.jpg").write_bytes(b"x") + with patch("scripts.twitter_threads.download_media.subprocess.run", MagicMock(return_value=MagicMock(returncode=0))): + code = download_main(["--input", str(thread_data_json), "--output", "./" + str(mediadir).replace("\\", "/") + "/"]) + assert code == 0 + assert (mediadir / "9_1.jpg").exists()