| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 |
- import { createParserConfig } from './cli'
- import { parse as parseShellCommand } from 'shell-quote'
- export function isTabbyURL (arg: string): boolean {
- return arg.toLowerCase().startsWith('tabby://')
- }
- export function parseTabbyURL (url: string, cwd: string = process.cwd()): any {
- try {
- if (!isTabbyURL(url)) {
- return null
- }
- // NOTE: the url host may be lowercased (xdg-open), need to use the original command
- const urlInstance = new URL(url)
- const command = urlInstance.host || urlInstance.pathname.replace(/^\/+/, '')
- const config = createParserConfig(cwd)
- const commandConfig = config.commands.find(cmd => {
- const primaryCommand = Array.isArray(cmd.command) ? cmd.command[0] : cmd.command
- return command.toLowerCase() === primaryCommand.split(/\s+/)[0].toLowerCase()
- })
- if (!commandConfig) {
- console.error(`Unknown command in tabby:// URL: ${command}`)
- return null
- }
- const primaryCommand = Array.isArray(commandConfig.command) ? commandConfig.command[0] : commandConfig.command
- const actualCommand = primaryCommand.split(/\s+/)[0]
- const argv: any = {
- _: [actualCommand],
- }
- for (const [key, value] of urlInstance.searchParams.entries()) {
- let parsedValue: any = value
- const optionConfig = commandConfig.options?.[key] ?? commandConfig.positionals?.[key]
- if (optionConfig) {
- switch (optionConfig.type) {
- case 'boolean':
- parsedValue = value === 'true' || value === ''
- break
- case 'number':
- parsedValue = parseInt(value, 10)
- break
- case 'array':
- parsedValue = parseShellCommand(value).filter(item => typeof item === 'string')
- break
- case 'string':
- default:
- parsedValue = value
- break
- }
- } else {
- parsedValue = value
- }
- argv[key] = parsedValue
- }
- console.log(`URL Handler - Safely parsed [${url}] to:`, JSON.stringify(argv))
- return argv
- } catch (e) {
- console.error('Failed to parse tabby:// URL:', e)
- return null
- }
- }
|