WIP: A simple cli for daily tangled use cases and AI integration. This is for my personal use right now, but happy if others get mileage from it! :)

Add biome v2 and apply format/lint changes.

markbennett.ca fb86993c e94a2d76

verified
+66 -58
+10 -5
biome.json
··· 1 1 { 2 - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 2 + "$schema": "https://biomejs.dev/schemas/2.3.14/schema.json", 3 3 "vcs": { 4 4 "enabled": true, 5 5 "clientKind": "git", ··· 7 7 }, 8 8 "files": { 9 9 "ignoreUnknown": false, 10 - "ignore": ["node_modules", "dist", "coverage", "src/lexicon/**", "lexicons/**"] 10 + "includes": [ 11 + "**", 12 + "!**/node_modules", 13 + "!**/dist", 14 + "!**/coverage", 15 + "!**/src/lexicon", 16 + "!**/lexicons" 17 + ] 11 18 }, 12 19 "formatter": { 13 20 "enabled": true, ··· 35 42 "semicolons": "always" 36 43 } 37 44 }, 38 - "organizeImports": { 39 - "enabled": true 40 - } 45 + "assist": { "actions": { "source": { "organizeImports": "on" } } } 41 46 }
+36 -37
package-lock.json
··· 24 24 }, 25 25 "devDependencies": { 26 26 "@atproto/lex-cli": "^0.9.8", 27 - "@biomejs/biome": "^1.9.4", 27 + "@biomejs/biome": "^2.3.14", 28 28 "@types/node": "^22.10.2", 29 29 "tsx": "^4.21.0", 30 30 "typescript": "^5.7.2", ··· 219 219 } 220 220 }, 221 221 "node_modules/@biomejs/biome": { 222 - "version": "1.9.4", 223 - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz", 224 - "integrity": "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==", 222 + "version": "2.3.14", 223 + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.14.tgz", 224 + "integrity": "sha512-QMT6QviX0WqXJCaiqVMiBUCr5WRQ1iFSjvOLoTk6auKukJMvnMzWucXpwZB0e8F00/1/BsS9DzcKgWH+CLqVuA==", 225 225 "dev": true, 226 - "hasInstallScript": true, 227 226 "license": "MIT OR Apache-2.0", 228 227 "bin": { 229 228 "biome": "bin/biome" ··· 236 235 "url": "https://opencollective.com/biome" 237 236 }, 238 237 "optionalDependencies": { 239 - "@biomejs/cli-darwin-arm64": "1.9.4", 240 - "@biomejs/cli-darwin-x64": "1.9.4", 241 - "@biomejs/cli-linux-arm64": "1.9.4", 242 - "@biomejs/cli-linux-arm64-musl": "1.9.4", 243 - "@biomejs/cli-linux-x64": "1.9.4", 244 - "@biomejs/cli-linux-x64-musl": "1.9.4", 245 - "@biomejs/cli-win32-arm64": "1.9.4", 246 - "@biomejs/cli-win32-x64": "1.9.4" 238 + "@biomejs/cli-darwin-arm64": "2.3.14", 239 + "@biomejs/cli-darwin-x64": "2.3.14", 240 + "@biomejs/cli-linux-arm64": "2.3.14", 241 + "@biomejs/cli-linux-arm64-musl": "2.3.14", 242 + "@biomejs/cli-linux-x64": "2.3.14", 243 + "@biomejs/cli-linux-x64-musl": "2.3.14", 244 + "@biomejs/cli-win32-arm64": "2.3.14", 245 + "@biomejs/cli-win32-x64": "2.3.14" 247 246 } 248 247 }, 249 248 "node_modules/@biomejs/cli-darwin-arm64": { 250 - "version": "1.9.4", 251 - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz", 252 - "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==", 249 + "version": "2.3.14", 250 + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.14.tgz", 251 + "integrity": "sha512-UJGPpvWJMkLxSRtpCAKfKh41Q4JJXisvxZL8ChN1eNW3m/WlPFJ6EFDCE7YfUb4XS8ZFi3C1dFpxUJ0Ety5n+A==", 253 252 "cpu": [ 254 253 "arm64" 255 254 ], ··· 264 263 } 265 264 }, 266 265 "node_modules/@biomejs/cli-darwin-x64": { 267 - "version": "1.9.4", 268 - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz", 269 - "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==", 266 + "version": "2.3.14", 267 + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.14.tgz", 268 + "integrity": "sha512-PNkLNQG6RLo8lG7QoWe/hhnMxJIt1tEimoXpGQjwS/dkdNiKBLPv4RpeQl8o3s1OKI3ZOR5XPiYtmbGGHAOnLA==", 270 269 "cpu": [ 271 270 "x64" 272 271 ], ··· 281 280 } 282 281 }, 283 282 "node_modules/@biomejs/cli-linux-arm64": { 284 - "version": "1.9.4", 285 - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz", 286 - "integrity": "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==", 283 + "version": "2.3.14", 284 + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.14.tgz", 285 + "integrity": "sha512-KT67FKfzIw6DNnUNdYlBg+eU24Go3n75GWK6NwU4+yJmDYFe9i/MjiI+U/iEzKvo0g7G7MZqoyrhIYuND2w8QQ==", 287 286 "cpu": [ 288 287 "arm64" 289 288 ], ··· 298 297 } 299 298 }, 300 299 "node_modules/@biomejs/cli-linux-arm64-musl": { 301 - "version": "1.9.4", 302 - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz", 303 - "integrity": "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==", 300 + "version": "2.3.14", 301 + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.14.tgz", 302 + "integrity": "sha512-LInRbXhYujtL3sH2TMCH/UBwJZsoGwfQjBrMfl84CD4hL/41C/EU5mldqf1yoFpsI0iPWuU83U+nB2TUUypWeg==", 304 303 "cpu": [ 305 304 "arm64" 306 305 ], ··· 315 314 } 316 315 }, 317 316 "node_modules/@biomejs/cli-linux-x64": { 318 - "version": "1.9.4", 319 - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz", 320 - "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==", 317 + "version": "2.3.14", 318 + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.14.tgz", 319 + "integrity": "sha512-ZsZzQsl9U+wxFrGGS4f6UxREUlgHwmEfu1IrXlgNFrNnd5Th6lIJr8KmSzu/+meSa9f4rzFrbEW9LBBA6ScoMA==", 321 320 "cpu": [ 322 321 "x64" 323 322 ], ··· 332 331 } 333 332 }, 334 333 "node_modules/@biomejs/cli-linux-x64-musl": { 335 - "version": "1.9.4", 336 - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz", 337 - "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==", 334 + "version": "2.3.14", 335 + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.14.tgz", 336 + "integrity": "sha512-KQU7EkbBBuHPW3/rAcoiVmhlPtDSGOGRPv9js7qJVpYTzjQmVR+C9Rfcz+ti8YCH+zT1J52tuBybtP4IodjxZQ==", 338 337 "cpu": [ 339 338 "x64" 340 339 ], ··· 349 348 } 350 349 }, 351 350 "node_modules/@biomejs/cli-win32-arm64": { 352 - "version": "1.9.4", 353 - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz", 354 - "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==", 351 + "version": "2.3.14", 352 + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.14.tgz", 353 + "integrity": "sha512-+IKYkj/pUBbnRf1G1+RlyA3LWiDgra1xpS7H2g4BuOzzRbRB+hmlw0yFsLprHhbbt7jUzbzAbAjK/Pn0FDnh1A==", 355 354 "cpu": [ 356 355 "arm64" 357 356 ], ··· 366 365 } 367 366 }, 368 367 "node_modules/@biomejs/cli-win32-x64": { 369 - "version": "1.9.4", 370 - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", 371 - "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==", 368 + "version": "2.3.14", 369 + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.14.tgz", 370 + "integrity": "sha512-oizCjdyQ3WJEswpb3Chdngeat56rIdSYK12JI3iI11Mt5T5EXcZ7WLuowzEaFPNJ3zmOQFliMN8QY1Pi+qsfdQ==", 372 371 "cpu": [ 373 372 "x64" 374 373 ],
+8 -2
package.json
··· 28 28 "type": "git", 29 29 "url": "git@tangled.org:markbennett.ca/tangled-cli" 30 30 }, 31 - "keywords": ["git", "tangled", "pds", "atproto", "cli"], 31 + "keywords": [ 32 + "git", 33 + "tangled", 34 + "pds", 35 + "atproto", 36 + "cli" 37 + ], 32 38 "author": "Mark Bennett", 33 39 "license": "MIT", 34 40 "dependencies": { ··· 44 50 }, 45 51 "devDependencies": { 46 52 "@atproto/lex-cli": "^0.9.8", 47 - "@biomejs/biome": "^1.9.4", 53 + "@biomejs/biome": "^2.3.14", 48 54 "@types/node": "^22.10.2", 49 55 "tsx": "^4.21.0", 50 56 "typescript": "^5.7.2",
+2 -2
scripts/fix-lexicon-imports.js
··· 8 8 * 3. Ensures proper TypeScript compatibility with NodeNext module resolution 9 9 */ 10 10 11 - import { readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs'; 11 + import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'; 12 12 import { join } from 'node:path'; 13 13 14 14 // Recursively find all .ts files in a directory ··· 52 52 // Match: from '../../something' or from "../something" 53 53 // But don't match if it already has an extension 54 54 const relativeImportRegex = /from\s+['"](\.\.[^'"]*?)(?<!\.js|\.ts)['"]/g; 55 - modified = modified.replace(relativeImportRegex, (match, path) => { 55 + modified = modified.replace(relativeImportRegex, (_match, path) => { 56 56 fileChanges++; 57 57 return `from '${path}.js'`; 58 58 });
+1 -1
src/commands/config.ts
··· 3 3 import { dirname, join } from 'node:path'; 4 4 import { Command } from 'commander'; 5 5 import { simpleGit } from 'simple-git'; 6 - import { type TangledConfig, loadConfig } from '../lib/config.js'; 6 + import { loadConfig, type TangledConfig } from '../lib/config.js'; 7 7 8 8 /** 9 9 * Get Git root directory
+2 -2
src/commands/issue.ts
··· 1 1 import { confirm } from '@inquirer/prompts'; 2 2 import { Command } from 'commander'; 3 - import { createApiClient } from '../lib/api-client.js'; 4 3 import type { TangledApiClient } from '../lib/api-client.js'; 4 + import { createApiClient } from '../lib/api-client.js'; 5 5 import { getCurrentRepoContext } from '../lib/context.js'; 6 + import type { IssueData } from '../lib/issues-api.js'; 6 7 import { 7 8 closeIssue, 8 9 createIssue, ··· 14 15 resolveSequentialNumber, 15 16 updateIssue, 16 17 } from '../lib/issues-api.js'; 17 - import type { IssueData } from '../lib/issues-api.js'; 18 18 import { buildRepoAtUri } from '../utils/at-uri.js'; 19 19 import { ensureAuthenticated, requireAuth } from '../utils/auth-helpers.js'; 20 20 import { readBodyInput } from '../utils/body-input.js';
+2 -2
src/lib/api-client.ts
··· 1 - import { AtpAgent } from '@atproto/api'; 2 1 import type { AtpSessionData } from '@atproto/api'; 2 + import { AtpAgent } from '@atproto/api'; 3 3 import { 4 - KeychainAccessError, 5 4 clearCurrentSessionMetadata, 6 5 deleteSession, 7 6 getCurrentSessionMetadata, 7 + KeychainAccessError, 8 8 loadSession, 9 9 saveCurrentSessionMetadata, 10 10 saveSession,
+1 -1
src/lib/context.ts
··· 61 61 } 62 62 63 63 return tangledRemotes; 64 - } catch (error) { 64 + } catch { 65 65 // Git errors - return empty array 66 66 return []; 67 67 }
+2 -2
tests/commands/issue.test.ts
··· 1 1 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; 2 2 import { createIssueCommand } from '../../src/commands/issue.js'; 3 - import * as apiClient from '../../src/lib/api-client.js'; 4 3 import type { TangledApiClient } from '../../src/lib/api-client.js'; 4 + import * as apiClient from '../../src/lib/api-client.js'; 5 5 import * as context from '../../src/lib/context.js'; 6 - import * as issuesApi from '../../src/lib/issues-api.js'; 7 6 import type { IssueWithMetadata } from '../../src/lib/issues-api.js'; 7 + import * as issuesApi from '../../src/lib/issues-api.js'; 8 8 import * as atUri from '../../src/utils/at-uri.js'; 9 9 import * as authHelpers from '../../src/utils/auth-helpers.js'; 10 10 import * as bodyInput from '../../src/utils/body-input.js';
+2 -2
tests/lib/api-client.test.ts
··· 1 1 import type { AtpSessionData } from '@atproto/api'; 2 2 import { beforeEach, describe, expect, it, vi } from 'vitest'; 3 3 import { TangledApiClient } from '../../src/lib/api-client.js'; 4 - import { KeychainAccessError } from '../../src/lib/session.js'; 5 4 import * as sessionModule from '../../src/lib/session.js'; 5 + import { KeychainAccessError } from '../../src/lib/session.js'; 6 6 import { mockSessionData, mockSessionMetadata } from '../helpers/mock-data.js'; 7 7 8 8 // Mock @atproto/api 9 9 vi.mock('@atproto/api', () => { 10 10 return { 11 11 AtpAgent: vi.fn().mockImplementation(() => { 12 - let currentSession: AtpSessionData | undefined = undefined; 12 + let currentSession: AtpSessionData | undefined; 13 13 14 14 return { 15 15 service: { toString: () => 'https://bsky.social' },
-2
tests/lib/config.test.ts
··· 26 26 beforeEach(() => { 27 27 vi.clearAllMocks(); 28 28 originalEnv = process.env.TANGLED_REMOTE; 29 - // biome-ignore lint/performance/noDelete: Need to actually delete env var, not set to undefined 30 29 delete process.env.TANGLED_REMOTE; 31 30 }); 32 31 ··· 34 33 if (originalEnv !== undefined) { 35 34 process.env.TANGLED_REMOTE = originalEnv; 36 35 } else { 37 - // biome-ignore lint/performance/noDelete: Need to actually delete env var, not set to undefined 38 36 delete process.env.TANGLED_REMOTE; 39 37 } 40 38 });