@rejot-dev/thalo-cli 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,8 +37,8 @@ The `thalo format` command requires the optional `@rejot-dev/thalo-prettier` plu
37
37
  npm install @rejot-dev/thalo-prettier
38
38
  ```
39
39
 
40
- Note: `thalo-prettier` requires native tree-sitter bindings. If compilation fails on Node.js 24+,
41
- use Node.js 22 LTS for formatting. All other CLI commands work on Node.js 24+ via WASM fallback.
40
+ Note: `thalo-prettier` prefers native tree-sitter bindings but will fall back to WASM if native
41
+ bindings are unavailable. All other CLI commands work on Node.js 24+ via WASM fallback.
42
42
 
43
43
  ## Usage
44
44
 
@@ -76,8 +76,7 @@ async function createPrettierFormatter() {
76
76
  console.error();
77
77
  console.error(pc.cyan(" npm install @rejot-dev/thalo-prettier"));
78
78
  console.error();
79
- console.error(pc.dim("Note: thalo-prettier requires native tree-sitter bindings."));
80
- console.error(pc.dim("If compilation fails on Node.js 24+, use Node.js 22 LTS instead."));
79
+ console.error(pc.dim("Note: thalo-prettier prefers native tree-sitter bindings but will fall back to WASM if needed."));
81
80
  process.exit(1);
82
81
  }
83
82
  return async (source, filepath) => {
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","names":["files: string[]","stat","thaloPrettier: Awaited<typeof import(\"@rejot-dev/thalo-prettier\")>","resolve","result","files: FormatFileInput[]","result: FormatResult","parts: string[]","formatCommand: CommandDef"],"sources":["../../src/commands/format.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport ignore from \"ignore\";\nimport pc from \"picocolors\";\nimport type { CommandDef, CommandContext } from \"../cli.js\";\nimport { createWorkspace } from \"@rejot-dev/thalo/node\";\nimport {\n runFormat,\n type FormatResult,\n type FormatFileInput,\n type SyntaxErrorInfo,\n} from \"@rejot-dev/thalo\";\nimport { relativePath } from \"../files.js\";\n\n// ===================\n// File Collection (format-specific with ignore patterns)\n// ===================\n\nasync function loadIgnoreFile(filePath: string): Promise<string[]> {\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n return content.split(\"\\n\").filter((line) => line.trim() && !line.startsWith(\"#\"));\n } catch {\n return [];\n }\n}\n\nasync function createIgnoreFilter(dir: string) {\n const ig = ignore();\n ig.add(await loadIgnoreFile(path.join(dir, \".gitignore\")));\n ig.add(await loadIgnoreFile(path.join(dir, \".prettierignore\")));\n return ig;\n}\n\nasync function collectFilesWithIgnore(dir: string, fileTypes: string[]): Promise<string[]> {\n const files: string[] = [];\n const ig = await createIgnoreFilter(dir);\n\n // Build glob patterns for each file type\n const patterns = fileTypes.map((type) => `**/*.${type}`);\n\n // exclude prevents traversing into node_modules/.git (perf), ig.ignores handles user patterns\n for (const pattern of patterns) {\n for await (const entry of fs.glob(pattern, {\n cwd: dir,\n exclude: (name) => name === \"node_modules\" || name.startsWith(\".\"),\n })) {\n // Normalize to forward slashes for ignore matching (ignore lib expects posix paths)\n const igPath = entry.split(path.sep).join(\"/\");\n if (!ig.ignores(igPath)) {\n files.push(path.join(dir, entry));\n }\n }\n }\n\n return files;\n}\n\nasync function resolveFormatFiles(paths: string[], fileTypes: string[]): Promise<string[]> {\n const files: string[] = [];\n\n for (const targetPath of paths) {\n const resolved = path.resolve(targetPath);\n\n try {\n const stat = await fs.stat(resolved);\n if (stat.isDirectory()) {\n files.push(...(await collectFilesWithIgnore(resolved, fileTypes)));\n } else if (stat.isFile()) {\n const ext = path.extname(resolved).slice(1); // Remove leading dot\n if (fileTypes.includes(ext)) {\n files.push(resolved);\n }\n }\n } catch {\n console.error(pc.red(`Error: Path not found: ${targetPath}`));\n process.exit(2);\n }\n }\n\n return files;\n}\n\nfunction formatSyntaxError(error: SyntaxErrorInfo): string {\n const loc = `${error.line}:${error.column}`.padEnd(8);\n const severityLabel = pc.red(\"error\".padEnd(7));\n const codeLabel = pc.dim(error.code);\n\n return ` ${pc.dim(loc)} ${severityLabel} ${error.message} ${codeLabel}`;\n}\n\n// ===================\n// Prettier Integration\n// ===================\n\nfunction getParser(filePath: string): string {\n const ext = path.extname(filePath).slice(1);\n if (ext === \"thalo\") {\n return \"thalo\";\n }\n if (ext === \"md\") {\n return \"markdown\";\n }\n return \"thalo\"; // default\n}\n\nasync function createPrettierFormatter(): Promise<\n (source: string, filepath: string) => Promise<string>\n> {\n const prettier = await import(\"prettier\");\n\n let thaloPrettier: Awaited<typeof import(\"@rejot-dev/thalo-prettier\")>;\n try {\n thaloPrettier = await import(\"@rejot-dev/thalo-prettier\");\n } catch {\n console.error(pc.red(\"Error: @rejot-dev/thalo-prettier is not installed.\"));\n console.error();\n console.error(\"The 'format' command requires the thalo-prettier plugin.\");\n console.error(\"Install it with:\");\n console.error();\n console.error(pc.cyan(\" npm install @rejot-dev/thalo-prettier\"));\n console.error();\n console.error(pc.dim(\"Note: thalo-prettier requires native tree-sitter bindings.\"));\n console.error(pc.dim(\"If compilation fails on Node.js 24+, use Node.js 22 LTS instead.\"));\n process.exit(1);\n }\n\n return async (source: string, filepath: string): Promise<string> => {\n const parser = getParser(filepath);\n // Load project's prettier config (prettier.config.mjs, .prettierrc, etc.)\n const resolvedConfig = await prettier.resolveConfig(filepath);\n return prettier.format(source, {\n ...resolvedConfig,\n filepath,\n parser,\n plugins: [thaloPrettier],\n });\n };\n}\n\n// ===================\n// Command Action\n// ===================\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = \"\";\n let settled = false;\n process.stdin.setEncoding(\"utf-8\");\n\n const cleanup = () => {\n process.stdin.removeListener(\"data\", onData);\n process.stdin.removeListener(\"end\", onEnd);\n process.stdin.removeListener(\"error\", onError);\n process.stdin.removeListener(\"close\", onClose);\n };\n\n const settle = (fn: () => void) => {\n if (!settled) {\n settled = true;\n cleanup();\n fn();\n }\n };\n\n const onData = (chunk: string) => {\n data += chunk;\n };\n\n const onEnd = () => {\n settle(() => resolve(data));\n };\n\n const onError = (error: Error) => {\n settle(() => reject(error));\n };\n\n const onClose = () => {\n // This handles cases where stdin closes without 'end' (e.g., EOF)\n settle(() => resolve(data));\n };\n\n // 'data' can fire multiple times, so use 'on'\n process.stdin.on(\"data\", onData);\n // 'end', 'error', and 'close' should only fire once, so use 'once'\n process.stdin.once(\"end\", onEnd);\n process.stdin.once(\"error\", onError);\n process.stdin.once(\"close\", onClose);\n });\n}\n\nasync function formatAction(ctx: CommandContext): Promise<void> {\n const { options, args } = ctx;\n const checkOnly = options[\"check\"] as boolean;\n const writeBack = options[\"write\"] as boolean;\n const useStdin = options[\"stdin\"] as boolean;\n const fileTypeStr = (options[\"file-type\"] as string) || \"md,thalo\";\n const fileTypes = fileTypeStr.split(\",\").map((t) => t.trim());\n\n // Handle stdin mode - read from stdin, output to stdout\n if (useStdin) {\n const content = await readStdin();\n const workspace = createWorkspace();\n const formatter = await createPrettierFormatter();\n\n // Use a placeholder filepath for parser detection (default to .thalo)\n const filepath = args[0] || \"stdin.thalo\";\n const files: FormatFileInput[] = [{ file: filepath, content }];\n const result = await runFormat(workspace, files, { formatter });\n\n const fileResult = result.fileResults[0];\n if (fileResult) {\n // Output formatted content to stdout\n process.stdout.write(fileResult.formatted);\n }\n\n // Exit with error code if there were syntax errors\n if (result.syntaxErrorCount > 0) {\n process.exit(1);\n }\n return;\n }\n\n const targetPaths = args.length > 0 ? args : [\".\"];\n const filePaths = await resolveFormatFiles(targetPaths, fileTypes);\n\n if (filePaths.length === 0) {\n const fileTypesStr = fileTypes.join(\", \");\n console.log(`No .${fileTypesStr} files found.`);\n process.exit(0);\n }\n\n // Read all file contents\n const files: FormatFileInput[] = await Promise.all(\n filePaths.map(async (file) => ({\n file,\n content: await fs.readFile(file, \"utf-8\"),\n })),\n );\n\n // Create workspace and formatter\n const workspace = createWorkspace();\n const formatter = await createPrettierFormatter();\n\n // Run format\n const result: FormatResult = await runFormat(workspace, files, { formatter });\n\n // Output results\n let writeCount = 0;\n\n for (const fileResult of result.fileResults) {\n const relPath = relativePath(fileResult.file);\n\n if (fileResult.hasSyntaxErrors) {\n // File has syntax errors - mark as failed\n console.log(pc.bold(pc.red(`✗`) + ` ${relPath}`));\n } else if (checkOnly) {\n if (fileResult.isChanged) {\n // Make files needing formatting bold with ✗\n console.log(pc.bold(pc.red(`✗`) + ` ${relPath}`));\n } else {\n // Files already formatted\n console.log(pc.green(`✓`) + ` ${relPath}`);\n }\n } else if (writeBack) {\n if (fileResult.isChanged) {\n await fs.writeFile(fileResult.file, fileResult.formatted, \"utf-8\");\n // Make formatted files bold (like prettier)\n console.log(pc.bold(pc.green(`✓`) + ` ${relPath}`));\n writeCount++;\n } else {\n // Print unchanged files in regular text\n console.log(pc.green(`✓`) + ` ${relPath}`);\n }\n } else {\n // This branch shouldn't happen since write defaults to true, but keep for safety\n if (fileResult.isChanged) {\n console.log(pc.yellow(`⚠`) + ` ${relPath} (needs formatting)`);\n } else {\n console.log(pc.green(`✓`) + ` ${relPath}`);\n }\n }\n }\n\n // Print syntax errors grouped by file (like check command does)\n const filesWithErrors = result.fileResults.filter((r) => r.hasSyntaxErrors);\n if (filesWithErrors.length > 0) {\n console.log();\n for (const fileResult of filesWithErrors) {\n console.log();\n console.log(pc.underline(relativePath(fileResult.file)));\n for (const error of fileResult.syntaxErrors) {\n console.log(formatSyntaxError(error));\n }\n }\n }\n\n // Print summary\n if (result.filesProcessed > 1 || checkOnly) {\n console.log();\n if (checkOnly) {\n const totalIssues = result.changedCount + result.syntaxErrorCount;\n if (totalIssues > 0) {\n const parts: string[] = [];\n if (result.syntaxErrorCount > 0) {\n parts.push(\n pc.red(\n `${result.syntaxErrorCount} file${result.syntaxErrorCount !== 1 ? \"s\" : \"\"} with syntax errors`,\n ),\n );\n }\n if (result.changedCount > 0) {\n parts.push(\n pc.yellow(\n `${result.changedCount} file${result.changedCount !== 1 ? \"s\" : \"\"} need${result.changedCount === 1 ? \"s\" : \"\"} formatting`,\n ),\n );\n }\n console.log(parts.join(\", \"));\n process.exit(1);\n } else {\n console.log(pc.green(`All ${result.filesProcessed} files are properly formatted`));\n }\n } else if (writeBack) {\n console.log(`Formatted ${writeCount} file${writeCount !== 1 ? \"s\" : \"\"}`);\n }\n }\n\n if (result.syntaxErrorCount > 0) {\n process.exit(1);\n }\n}\n\nexport const formatCommand: CommandDef = {\n name: \"format\",\n description: \"Format thalo and markdown files using Prettier\",\n args: {\n name: \"paths\",\n description: \"Files or directories to format\",\n required: false,\n multiple: true,\n },\n options: {\n check: {\n type: \"boolean\",\n short: \"c\",\n description: \"Check if files are formatted (exit 1 if not)\",\n default: false,\n },\n write: {\n type: \"boolean\",\n short: \"w\",\n description: \"Write formatted output back to files\",\n default: true,\n },\n stdin: {\n type: \"boolean\",\n description: \"Read from stdin and output to stdout (for editor integration)\",\n default: false,\n },\n \"file-type\": {\n type: \"string\",\n description: \"Comma-separated list of file types to format (e.g., 'md,thalo')\",\n default: \"md,thalo\",\n },\n },\n action: formatAction,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"format.js","names":["files: string[]","stat","thaloPrettier: Awaited<typeof import(\"@rejot-dev/thalo-prettier\")>","resolve","result","files: FormatFileInput[]","result: FormatResult","parts: string[]","formatCommand: CommandDef"],"sources":["../../src/commands/format.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport ignore from \"ignore\";\nimport pc from \"picocolors\";\nimport type { CommandDef, CommandContext } from \"../cli.js\";\nimport { createWorkspace } from \"@rejot-dev/thalo/node\";\nimport {\n runFormat,\n type FormatResult,\n type FormatFileInput,\n type SyntaxErrorInfo,\n} from \"@rejot-dev/thalo\";\nimport { relativePath } from \"../files.js\";\n\n// ===================\n// File Collection (format-specific with ignore patterns)\n// ===================\n\nasync function loadIgnoreFile(filePath: string): Promise<string[]> {\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n return content.split(\"\\n\").filter((line) => line.trim() && !line.startsWith(\"#\"));\n } catch {\n return [];\n }\n}\n\nasync function createIgnoreFilter(dir: string) {\n const ig = ignore();\n ig.add(await loadIgnoreFile(path.join(dir, \".gitignore\")));\n ig.add(await loadIgnoreFile(path.join(dir, \".prettierignore\")));\n return ig;\n}\n\nasync function collectFilesWithIgnore(dir: string, fileTypes: string[]): Promise<string[]> {\n const files: string[] = [];\n const ig = await createIgnoreFilter(dir);\n\n // Build glob patterns for each file type\n const patterns = fileTypes.map((type) => `**/*.${type}`);\n\n // exclude prevents traversing into node_modules/.git (perf), ig.ignores handles user patterns\n for (const pattern of patterns) {\n for await (const entry of fs.glob(pattern, {\n cwd: dir,\n exclude: (name) => name === \"node_modules\" || name.startsWith(\".\"),\n })) {\n // Normalize to forward slashes for ignore matching (ignore lib expects posix paths)\n const igPath = entry.split(path.sep).join(\"/\");\n if (!ig.ignores(igPath)) {\n files.push(path.join(dir, entry));\n }\n }\n }\n\n return files;\n}\n\nasync function resolveFormatFiles(paths: string[], fileTypes: string[]): Promise<string[]> {\n const files: string[] = [];\n\n for (const targetPath of paths) {\n const resolved = path.resolve(targetPath);\n\n try {\n const stat = await fs.stat(resolved);\n if (stat.isDirectory()) {\n files.push(...(await collectFilesWithIgnore(resolved, fileTypes)));\n } else if (stat.isFile()) {\n const ext = path.extname(resolved).slice(1); // Remove leading dot\n if (fileTypes.includes(ext)) {\n files.push(resolved);\n }\n }\n } catch {\n console.error(pc.red(`Error: Path not found: ${targetPath}`));\n process.exit(2);\n }\n }\n\n return files;\n}\n\nfunction formatSyntaxError(error: SyntaxErrorInfo): string {\n const loc = `${error.line}:${error.column}`.padEnd(8);\n const severityLabel = pc.red(\"error\".padEnd(7));\n const codeLabel = pc.dim(error.code);\n\n return ` ${pc.dim(loc)} ${severityLabel} ${error.message} ${codeLabel}`;\n}\n\n// ===================\n// Prettier Integration\n// ===================\n\nfunction getParser(filePath: string): string {\n const ext = path.extname(filePath).slice(1);\n if (ext === \"thalo\") {\n return \"thalo\";\n }\n if (ext === \"md\") {\n return \"markdown\";\n }\n return \"thalo\"; // default\n}\n\nasync function createPrettierFormatter(): Promise<\n (source: string, filepath: string) => Promise<string>\n> {\n const prettier = await import(\"prettier\");\n\n let thaloPrettier: Awaited<typeof import(\"@rejot-dev/thalo-prettier\")>;\n try {\n thaloPrettier = await import(\"@rejot-dev/thalo-prettier\");\n } catch {\n console.error(pc.red(\"Error: @rejot-dev/thalo-prettier is not installed.\"));\n console.error();\n console.error(\"The 'format' command requires the thalo-prettier plugin.\");\n console.error(\"Install it with:\");\n console.error();\n console.error(pc.cyan(\" npm install @rejot-dev/thalo-prettier\"));\n console.error();\n console.error(\n pc.dim(\n \"Note: thalo-prettier prefers native tree-sitter bindings but will fall back to WASM if needed.\",\n ),\n );\n process.exit(1);\n }\n\n return async (source: string, filepath: string): Promise<string> => {\n const parser = getParser(filepath);\n // Load project's prettier config (prettier.config.mjs, .prettierrc, etc.)\n const resolvedConfig = await prettier.resolveConfig(filepath);\n return prettier.format(source, {\n ...resolvedConfig,\n filepath,\n parser,\n plugins: [thaloPrettier],\n });\n };\n}\n\n// ===================\n// Command Action\n// ===================\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = \"\";\n let settled = false;\n process.stdin.setEncoding(\"utf-8\");\n\n const cleanup = () => {\n process.stdin.removeListener(\"data\", onData);\n process.stdin.removeListener(\"end\", onEnd);\n process.stdin.removeListener(\"error\", onError);\n process.stdin.removeListener(\"close\", onClose);\n };\n\n const settle = (fn: () => void) => {\n if (!settled) {\n settled = true;\n cleanup();\n fn();\n }\n };\n\n const onData = (chunk: string) => {\n data += chunk;\n };\n\n const onEnd = () => {\n settle(() => resolve(data));\n };\n\n const onError = (error: Error) => {\n settle(() => reject(error));\n };\n\n const onClose = () => {\n // This handles cases where stdin closes without 'end' (e.g., EOF)\n settle(() => resolve(data));\n };\n\n // 'data' can fire multiple times, so use 'on'\n process.stdin.on(\"data\", onData);\n // 'end', 'error', and 'close' should only fire once, so use 'once'\n process.stdin.once(\"end\", onEnd);\n process.stdin.once(\"error\", onError);\n process.stdin.once(\"close\", onClose);\n });\n}\n\nasync function formatAction(ctx: CommandContext): Promise<void> {\n const { options, args } = ctx;\n const checkOnly = options[\"check\"] as boolean;\n const writeBack = options[\"write\"] as boolean;\n const useStdin = options[\"stdin\"] as boolean;\n const fileTypeStr = (options[\"file-type\"] as string) || \"md,thalo\";\n const fileTypes = fileTypeStr.split(\",\").map((t) => t.trim());\n\n // Handle stdin mode - read from stdin, output to stdout\n if (useStdin) {\n const content = await readStdin();\n const workspace = createWorkspace();\n const formatter = await createPrettierFormatter();\n\n // Use a placeholder filepath for parser detection (default to .thalo)\n const filepath = args[0] || \"stdin.thalo\";\n const files: FormatFileInput[] = [{ file: filepath, content }];\n const result = await runFormat(workspace, files, { formatter });\n\n const fileResult = result.fileResults[0];\n if (fileResult) {\n // Output formatted content to stdout\n process.stdout.write(fileResult.formatted);\n }\n\n // Exit with error code if there were syntax errors\n if (result.syntaxErrorCount > 0) {\n process.exit(1);\n }\n return;\n }\n\n const targetPaths = args.length > 0 ? args : [\".\"];\n const filePaths = await resolveFormatFiles(targetPaths, fileTypes);\n\n if (filePaths.length === 0) {\n const fileTypesStr = fileTypes.join(\", \");\n console.log(`No .${fileTypesStr} files found.`);\n process.exit(0);\n }\n\n // Read all file contents\n const files: FormatFileInput[] = await Promise.all(\n filePaths.map(async (file) => ({\n file,\n content: await fs.readFile(file, \"utf-8\"),\n })),\n );\n\n // Create workspace and formatter\n const workspace = createWorkspace();\n const formatter = await createPrettierFormatter();\n\n // Run format\n const result: FormatResult = await runFormat(workspace, files, { formatter });\n\n // Output results\n let writeCount = 0;\n\n for (const fileResult of result.fileResults) {\n const relPath = relativePath(fileResult.file);\n\n if (fileResult.hasSyntaxErrors) {\n // File has syntax errors - mark as failed\n console.log(pc.bold(pc.red(`✗`) + ` ${relPath}`));\n } else if (checkOnly) {\n if (fileResult.isChanged) {\n // Make files needing formatting bold with ✗\n console.log(pc.bold(pc.red(`✗`) + ` ${relPath}`));\n } else {\n // Files already formatted\n console.log(pc.green(`✓`) + ` ${relPath}`);\n }\n } else if (writeBack) {\n if (fileResult.isChanged) {\n await fs.writeFile(fileResult.file, fileResult.formatted, \"utf-8\");\n // Make formatted files bold (like prettier)\n console.log(pc.bold(pc.green(`✓`) + ` ${relPath}`));\n writeCount++;\n } else {\n // Print unchanged files in regular text\n console.log(pc.green(`✓`) + ` ${relPath}`);\n }\n } else {\n // This branch shouldn't happen since write defaults to true, but keep for safety\n if (fileResult.isChanged) {\n console.log(pc.yellow(`⚠`) + ` ${relPath} (needs formatting)`);\n } else {\n console.log(pc.green(`✓`) + ` ${relPath}`);\n }\n }\n }\n\n // Print syntax errors grouped by file (like check command does)\n const filesWithErrors = result.fileResults.filter((r) => r.hasSyntaxErrors);\n if (filesWithErrors.length > 0) {\n console.log();\n for (const fileResult of filesWithErrors) {\n console.log();\n console.log(pc.underline(relativePath(fileResult.file)));\n for (const error of fileResult.syntaxErrors) {\n console.log(formatSyntaxError(error));\n }\n }\n }\n\n // Print summary\n if (result.filesProcessed > 1 || checkOnly) {\n console.log();\n if (checkOnly) {\n const totalIssues = result.changedCount + result.syntaxErrorCount;\n if (totalIssues > 0) {\n const parts: string[] = [];\n if (result.syntaxErrorCount > 0) {\n parts.push(\n pc.red(\n `${result.syntaxErrorCount} file${result.syntaxErrorCount !== 1 ? \"s\" : \"\"} with syntax errors`,\n ),\n );\n }\n if (result.changedCount > 0) {\n parts.push(\n pc.yellow(\n `${result.changedCount} file${result.changedCount !== 1 ? \"s\" : \"\"} need${result.changedCount === 1 ? \"s\" : \"\"} formatting`,\n ),\n );\n }\n console.log(parts.join(\", \"));\n process.exit(1);\n } else {\n console.log(pc.green(`All ${result.filesProcessed} files are properly formatted`));\n }\n } else if (writeBack) {\n console.log(`Formatted ${writeCount} file${writeCount !== 1 ? \"s\" : \"\"}`);\n }\n }\n\n if (result.syntaxErrorCount > 0) {\n process.exit(1);\n }\n}\n\nexport const formatCommand: CommandDef = {\n name: \"format\",\n description: \"Format thalo and markdown files using Prettier\",\n args: {\n name: \"paths\",\n description: \"Files or directories to format\",\n required: false,\n multiple: true,\n },\n options: {\n check: {\n type: \"boolean\",\n short: \"c\",\n description: \"Check if files are formatted (exit 1 if not)\",\n default: false,\n },\n write: {\n type: \"boolean\",\n short: \"w\",\n description: \"Write formatted output back to files\",\n default: true,\n },\n stdin: {\n type: \"boolean\",\n description: \"Read from stdin and output to stdout (for editor integration)\",\n default: false,\n },\n \"file-type\": {\n type: \"string\",\n description: \"Comma-separated list of file types to format (e.g., 'md,thalo')\",\n default: \"md,thalo\",\n },\n },\n action: formatAction,\n};\n"],"mappings":"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"}
@@ -39,7 +39,7 @@ const ENTITIES_THALO = `{{TIMESTAMP}} define-entity journal "Personal thoughts,
39
39
  # Metadata
40
40
  type: "fact" | "insight" ; "fact = verifiable info, insight = learned wisdom"
41
41
  subject: string | link ; "Subject name/slug (use ^self for personal lore)"
42
- date?: date-range ; "Relevant date or date range"
42
+ date?: daterange ; "Relevant date or date range"
43
43
  # Sections
44
44
  Description ; "The lore content"
45
45
 
@@ -47,73 +47,18 @@ const ENTITIES_THALO = `{{TIMESTAMP}} define-entity journal "Personal thoughts,
47
47
  # Sections
48
48
  Bio ; "Need at least one section"
49
49
  `;
50
- const AGENTS_MD = `# THALO - Thought And Lore Language
51
-
52
- Entity schemas are defined in \`entities.thalo\`.
53
-
54
- ## Entry Syntax
55
-
56
- \`\`\`
57
- {timestamp} {directive} {entity} "Title" [^link-id] [#tags...]
58
- {key}: {value}
59
- ...
60
-
61
- # Section
62
- {content}
63
-
64
- \`\`\`
65
-
66
- - **timestamp**: ISO 8601 local time with timezone (\`2026-01-05T15:30Z\`)
67
- - **directive**: \`create\` or \`update\`
68
- - **entity**: \`journal\`, \`opinion\`, \`reference\`, or \`lore\`
69
- - **^link-id**: Optional explicit ID for cross-referencing
70
- - **#tag**: Optional categorization tags
71
-
72
- ## Metadata
73
-
74
- Metadata fields are indented key-value pairs. See \`entities.thalo\` for required/optional
75
- fields per entity. Values can be:
76
-
77
- - Strings: \`author: "Jane Doe"\` or unquoted \`author: Jane Doe\`
78
- - Links: \`subject: ^self\` or \`related: ^my-other-entry\`
79
- - Dates: \`published: 2023-03-16\`
80
- - Date ranges: \`date: 2020 ~ 2021\`
81
-
82
- ## Sections
83
-
84
- Content sections start with \`# SectionName\` (indented). **All content must be within a section.**
85
- Each entity type defines which sections are required/optional in \`entities.thalo\`.
86
-
87
- ## Example
88
-
89
- \`\`\`thalo
90
- 2026-01-05T16:00Z create opinion "TypeScript enums should be avoided" ^opinion-ts-enums #typescript
91
- confidence: "high"
92
-
93
- # Claim
94
- TypeScript enums should be replaced with \`as const\` objects.
95
-
96
- # Reasoning
97
- - Enums generate runtime code
98
- - \`as const\` provides the same type safety with zero overhead
99
-
100
- \`\`\`
101
-
102
- ## Tips
103
-
104
- - Run \`date -u +"%Y-%m-%dT%H:%MZ"\` to get the current timestamp
105
- - Use \`thalo check\` to validate entries against schemas
106
- `;
107
- const PERSONAL_BIO_MD = `\`\`\`thalo
108
- {{TIMESTAMP}} define-synthesis "Personal Bio" ^bio-synthesis #profile
109
- sources: lore where subject = ^self
110
-
111
- # Prompt
112
- Write a narrative bio from the collected facts and insights.
113
- Keep it professional but personable.
114
- \`\`\`
115
-
116
- # Personal Bio
50
+ const REFERENCES_THALO = `{{TIMESTAMP}} create reference "A knowledge management system inspired by plain-text accounting" ^ref-thalo-intro #thalo
51
+ url: "https://thalo.rejot.dev/blog/plain-text-knowledge-management"
52
+ ref-type: "article"
53
+ author: "Wilco Kruijer"
54
+ published: 2026-01-26
55
+ status: "unread"
56
+
57
+ # Summary
58
+ Blog post introducing Thalo, a structured plain-text language for knowledge management inspired by
59
+ plain-text accounting (Beancount/Ledger). Argues that vibe note-taking lacks the feedback loops
60
+ that make agentic coding effective, and proposes treating knowledge bases like codebases: both are
61
+ folders of text files with relationships that compound when structured well.
117
62
  `;
118
63
  function initAction(ctx) {
119
64
  const { options, args } = ctx;
@@ -127,20 +72,13 @@ function initAction(ctx) {
127
72
  }
128
73
  console.log(pc.bold("Initializing THALO..."));
129
74
  console.log();
130
- const files = [
131
- {
132
- path: "entities.thalo",
133
- content: ENTITIES_THALO.replace(/\{\{TIMESTAMP\}\}/g, timestamp)
134
- },
135
- {
136
- path: "AGENTS.md",
137
- content: AGENTS_MD
138
- },
139
- {
140
- path: "personal-bio.md",
141
- content: PERSONAL_BIO_MD.replace(/\{\{TIMESTAMP\}\}/g, timestamp)
142
- }
143
- ];
75
+ const files = [{
76
+ path: "entities.thalo",
77
+ content: ENTITIES_THALO.replace(/\{\{TIMESTAMP\}\}/g, timestamp)
78
+ }, {
79
+ path: "references.thalo",
80
+ content: REFERENCES_THALO.replace(/\{\{TIMESTAMP\}\}/g, timestamp)
81
+ }];
144
82
  let createdCount = 0;
145
83
  let warningCount = 0;
146
84
  for (const file of files) {
@@ -163,7 +101,7 @@ function initAction(ctx) {
163
101
  }
164
102
  const initCommand = {
165
103
  name: "init",
166
- description: "Initialize THALO with entity definitions and documentation",
104
+ description: "Initialize THALO with entity definitions and starter references",
167
105
  args: {
168
106
  name: "directory",
169
107
  description: "Target directory (defaults to current directory)",
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","names":["initCommand: CommandDef"],"sources":["../../src/commands/init.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport pc from \"picocolors\";\nimport type { CommandDef, CommandContext } from \"../cli.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// File Templates\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst ENTITIES_THALO = `{{TIMESTAMP}} define-entity journal \"Personal thoughts, reflections, and experiences\" ^journal\n # Metadata\n subject: string | link ; \"Subject name/slug (use ^self for personal)\"\n type: string ; \"idea, reflection, experience, doubt, question, etc.\"\n mood?: string ; \"Free text mood\"\n context?: string ; \"What prompted this entry\"\n # Sections\n Entry ; \"The journal entry content\"\n\n{{TIMESTAMP}} define-entity opinion \"Formed stances on topics\" ^opinion\n # Metadata\n confidence: \"high\" | \"medium\" | \"low\"\n supersedes?: link ; \"Reference to previous stance\"\n related?: link[] ; \"Related entries\"\n # Sections\n Claim ; \"Core opinion in 1-2 sentences\"\n Reasoning ; \"Bullet points supporting the claim\"\n Caveats? ; \"Edge cases, limitations, exceptions\"\n\n{{TIMESTAMP}} define-entity reference \"External resources or local files\" ^reference\n # Metadata\n url?: string ; \"Full URL to external resource\"\n file?: string ; \"Path to local file\"\n ref-type: \"article\" | \"video\" | \"tweet\" | \"paper\" | \"book\" | \"other\"\n author?: string | link ; \"Creator/author name\"\n published?: datetime ; \"Publication date\"\n status?: \"unread\" | \"read\" | \"processed\" = \"unread\"\n # Sections\n Summary? ; \"Brief summary of the content\"\n Key Takeaways? ; \"Bullet points of main insights\"\n Related? ; \"Links to related entries\"\n\n{{TIMESTAMP}} define-entity lore \"Facts and insights about subjects or yourself\" ^lore\n # Metadata\n type: \"fact\" | \"insight\" ; \"fact = verifiable info, insight = learned wisdom\"\n subject: string | link ; \"Subject name/slug (use ^self for personal lore)\"\n date?: date-range ; \"Relevant date or date range\"\n # Sections\n Description ; \"The lore content\"\n\n{{TIMESTAMP}} define-entity me \"Entity to allow for self-references\" ^self\n # Sections\n Bio ; \"Need at least one section\"\n`;\n\nconst AGENTS_MD = `# THALO - Thought And Lore Language\n\nEntity schemas are defined in \\`entities.thalo\\`.\n\n## Entry Syntax\n\n\\`\\`\\`\n{timestamp} {directive} {entity} \"Title\" [^link-id] [#tags...]\n {key}: {value}\n ...\n\n # Section\n {content}\n\n\\`\\`\\`\n\n- **timestamp**: ISO 8601 local time with timezone (\\`2026-01-05T15:30Z\\`)\n- **directive**: \\`create\\` or \\`update\\`\n- **entity**: \\`journal\\`, \\`opinion\\`, \\`reference\\`, or \\`lore\\`\n- **^link-id**: Optional explicit ID for cross-referencing\n- **#tag**: Optional categorization tags\n\n## Metadata\n\nMetadata fields are indented key-value pairs. See \\`entities.thalo\\` for required/optional\nfields per entity. Values can be:\n\n- Strings: \\`author: \"Jane Doe\"\\` or unquoted \\`author: Jane Doe\\`\n- Links: \\`subject: ^self\\` or \\`related: ^my-other-entry\\`\n- Dates: \\`published: 2023-03-16\\`\n- Date ranges: \\`date: 2020 ~ 2021\\`\n\n## Sections\n\nContent sections start with \\`# SectionName\\` (indented). **All content must be within a section.**\nEach entity type defines which sections are required/optional in \\`entities.thalo\\`.\n\n## Example\n\n\\`\\`\\`thalo\n2026-01-05T16:00Z create opinion \"TypeScript enums should be avoided\" ^opinion-ts-enums #typescript\n confidence: \"high\"\n\n # Claim\n TypeScript enums should be replaced with \\`as const\\` objects.\n\n # Reasoning\n - Enums generate runtime code\n - \\`as const\\` provides the same type safety with zero overhead\n\n\\`\\`\\`\n\n## Tips\n\n- Run \\`date -u +\"%Y-%m-%dT%H:%MZ\"\\` to get the current timestamp\n- Use \\`thalo check\\` to validate entries against schemas\n`;\n\nconst PERSONAL_BIO_MD = `\\`\\`\\`thalo\n{{TIMESTAMP}} define-synthesis \"Personal Bio\" ^bio-synthesis #profile\n sources: lore where subject = ^self\n\n # Prompt\n Write a narrative bio from the collected facts and insights.\n Keep it professional but personable.\n\\`\\`\\`\n\n# Personal Bio\n`;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Init Action\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction initAction(ctx: CommandContext): void {\n const { options, args } = ctx;\n\n // Determine target directory\n const targetDir = args.length > 0 ? path.resolve(args[0]) : process.cwd();\n\n // Get current timestamp for entity definitions\n const now = new Date();\n const timestamp = now.toISOString().slice(0, 16) + \"Z\"; // YYYY-MM-DDTHH:MMZ\n\n const dryRun = options[\"dry-run\"] as boolean;\n const force = options[\"force\"] as boolean;\n\n if (dryRun) {\n console.log(pc.dim(\"Dry run mode - no files will be created\"));\n console.log();\n }\n\n console.log(pc.bold(\"Initializing THALO...\"));\n console.log();\n\n const files = [\n { path: \"entities.thalo\", content: ENTITIES_THALO.replace(/\\{\\{TIMESTAMP\\}\\}/g, timestamp) },\n { path: \"AGENTS.md\", content: AGENTS_MD },\n { path: \"personal-bio.md\", content: PERSONAL_BIO_MD.replace(/\\{\\{TIMESTAMP\\}\\}/g, timestamp) },\n ];\n\n let createdCount = 0;\n let warningCount = 0;\n\n for (const file of files) {\n const fullPath = path.join(targetDir, file.path);\n const exists = fs.existsSync(fullPath);\n\n if (exists && !force) {\n console.log(\n `${pc.yellow(\"⚠\")} ${pc.yellow(\"warning:\")} ${file.path} already exists, skipping`,\n );\n warningCount++;\n continue;\n }\n\n if (exists && force) {\n console.log(`${pc.yellow(\"⚠\")} ${pc.yellow(\"overwriting:\")} ${file.path}`);\n }\n\n if (!dryRun) {\n fs.writeFileSync(fullPath, file.content, \"utf-8\");\n }\n\n console.log(`${pc.green(\"✓\")} Created: ${pc.dim(file.path)}`);\n createdCount++;\n }\n\n // Summary\n console.log();\n if (warningCount > 0) {\n console.log(`${pc.yellow(\"Warnings:\")} ${warningCount} file(s) already exist`);\n }\n\n if (dryRun) {\n console.log(pc.dim(\"Run without --dry-run to create files.\"));\n } else if (createdCount > 0) {\n console.log(`${pc.green(\"✓\")} Done! Created ${createdCount} file(s).`);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Command Definition\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const initCommand: CommandDef = {\n name: \"init\",\n description: \"Initialize THALO with entity definitions and documentation\",\n args: {\n name: \"directory\",\n description: \"Target directory (defaults to current directory)\",\n required: false,\n multiple: false,\n },\n options: {\n \"dry-run\": {\n type: \"boolean\",\n short: \"n\",\n description: \"Show what would be created without making changes\",\n default: false,\n },\n force: {\n type: \"boolean\",\n short: \"f\",\n description: \"Overwrite existing files\",\n default: false,\n },\n },\n action: initAction,\n};\n"],"mappings":";;;;;AASA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CvB,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DlB,MAAM,kBAAkB;;;;;;;;;;;AAgBxB,SAAS,WAAW,KAA2B;CAC7C,MAAM,EAAE,SAAS,SAAS;CAG1B,MAAM,YAAY,KAAK,SAAS,IAAI,KAAK,QAAQ,KAAK,GAAG,GAAG,QAAQ,KAAK;CAIzE,MAAM,6BADM,IAAI,MAAM,EACA,aAAa,CAAC,MAAM,GAAG,GAAG,GAAG;CAEnD,MAAM,SAAS,QAAQ;CACvB,MAAM,QAAQ,QAAQ;AAEtB,KAAI,QAAQ;AACV,UAAQ,IAAI,GAAG,IAAI,0CAA0C,CAAC;AAC9D,UAAQ,KAAK;;AAGf,SAAQ,IAAI,GAAG,KAAK,wBAAwB,CAAC;AAC7C,SAAQ,KAAK;CAEb,MAAM,QAAQ;EACZ;GAAE,MAAM;GAAkB,SAAS,eAAe,QAAQ,sBAAsB,UAAU;GAAE;EAC5F;GAAE,MAAM;GAAa,SAAS;GAAW;EACzC;GAAE,MAAM;GAAmB,SAAS,gBAAgB,QAAQ,sBAAsB,UAAU;GAAE;EAC/F;CAED,IAAI,eAAe;CACnB,IAAI,eAAe;AAEnB,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAW,KAAK,KAAK,WAAW,KAAK,KAAK;EAChD,MAAM,SAAS,GAAG,WAAW,SAAS;AAEtC,MAAI,UAAU,CAAC,OAAO;AACpB,WAAQ,IACN,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,GAAG,OAAO,WAAW,CAAC,GAAG,KAAK,KAAK,2BACzD;AACD;AACA;;AAGF,MAAI,UAAU,MACZ,SAAQ,IAAI,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,GAAG,OAAO,eAAe,CAAC,GAAG,KAAK,OAAO;AAG5E,MAAI,CAAC,OACH,IAAG,cAAc,UAAU,KAAK,SAAS,QAAQ;AAGnD,UAAQ,IAAI,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,GAAG,IAAI,KAAK,KAAK,GAAG;AAC7D;;AAIF,SAAQ,KAAK;AACb,KAAI,eAAe,EACjB,SAAQ,IAAI,GAAG,GAAG,OAAO,YAAY,CAAC,GAAG,aAAa,wBAAwB;AAGhF,KAAI,OACF,SAAQ,IAAI,GAAG,IAAI,yCAAyC,CAAC;UACpD,eAAe,EACxB,SAAQ,IAAI,GAAG,GAAG,MAAM,IAAI,CAAC,iBAAiB,aAAa,WAAW;;AAQ1E,MAAaA,cAA0B;CACrC,MAAM;CACN,aAAa;CACb,MAAM;EACJ,MAAM;EACN,aAAa;EACb,UAAU;EACV,UAAU;EACX;CACD,SAAS;EACP,WAAW;GACT,MAAM;GACN,OAAO;GACP,aAAa;GACb,SAAS;GACV;EACD,OAAO;GACL,MAAM;GACN,OAAO;GACP,aAAa;GACb,SAAS;GACV;EACF;CACD,QAAQ;CACT"}
1
+ {"version":3,"file":"init.js","names":["initCommand: CommandDef"],"sources":["../../src/commands/init.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport pc from \"picocolors\";\nimport type { CommandDef, CommandContext } from \"../cli.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// File Templates\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst ENTITIES_THALO = `{{TIMESTAMP}} define-entity journal \"Personal thoughts, reflections, and experiences\" ^journal\n # Metadata\n subject: string | link ; \"Subject name/slug (use ^self for personal)\"\n type: string ; \"idea, reflection, experience, doubt, question, etc.\"\n mood?: string ; \"Free text mood\"\n context?: string ; \"What prompted this entry\"\n # Sections\n Entry ; \"The journal entry content\"\n\n{{TIMESTAMP}} define-entity opinion \"Formed stances on topics\" ^opinion\n # Metadata\n confidence: \"high\" | \"medium\" | \"low\"\n supersedes?: link ; \"Reference to previous stance\"\n related?: link[] ; \"Related entries\"\n # Sections\n Claim ; \"Core opinion in 1-2 sentences\"\n Reasoning ; \"Bullet points supporting the claim\"\n Caveats? ; \"Edge cases, limitations, exceptions\"\n\n{{TIMESTAMP}} define-entity reference \"External resources or local files\" ^reference\n # Metadata\n url?: string ; \"Full URL to external resource\"\n file?: string ; \"Path to local file\"\n ref-type: \"article\" | \"video\" | \"tweet\" | \"paper\" | \"book\" | \"other\"\n author?: string | link ; \"Creator/author name\"\n published?: datetime ; \"Publication date\"\n status?: \"unread\" | \"read\" | \"processed\" = \"unread\"\n # Sections\n Summary? ; \"Brief summary of the content\"\n Key Takeaways? ; \"Bullet points of main insights\"\n Related? ; \"Links to related entries\"\n\n{{TIMESTAMP}} define-entity lore \"Facts and insights about subjects or yourself\" ^lore\n # Metadata\n type: \"fact\" | \"insight\" ; \"fact = verifiable info, insight = learned wisdom\"\n subject: string | link ; \"Subject name/slug (use ^self for personal lore)\"\n date?: daterange ; \"Relevant date or date range\"\n # Sections\n Description ; \"The lore content\"\n\n{{TIMESTAMP}} define-entity me \"Entity to allow for self-references\" ^self\n # Sections\n Bio ; \"Need at least one section\"\n`;\n\nconst REFERENCES_THALO = `{{TIMESTAMP}} create reference \"A knowledge management system inspired by plain-text accounting\" ^ref-thalo-intro #thalo\n url: \"https://thalo.rejot.dev/blog/plain-text-knowledge-management\"\n ref-type: \"article\"\n author: \"Wilco Kruijer\"\n published: 2026-01-26\n status: \"unread\"\n\n # Summary\n Blog post introducing Thalo, a structured plain-text language for knowledge management inspired by\n plain-text accounting (Beancount/Ledger). Argues that vibe note-taking lacks the feedback loops\n that make agentic coding effective, and proposes treating knowledge bases like codebases: both are\n folders of text files with relationships that compound when structured well.\n`;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Init Action\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction initAction(ctx: CommandContext): void {\n const { options, args } = ctx;\n\n // Determine target directory\n const targetDir = args.length > 0 ? path.resolve(args[0]) : process.cwd();\n\n // Get current timestamp for entity definitions\n const now = new Date();\n const timestamp = now.toISOString().slice(0, 16) + \"Z\"; // YYYY-MM-DDTHH:MMZ\n\n const dryRun = options[\"dry-run\"] as boolean;\n const force = options[\"force\"] as boolean;\n\n if (dryRun) {\n console.log(pc.dim(\"Dry run mode - no files will be created\"));\n console.log();\n }\n\n console.log(pc.bold(\"Initializing THALO...\"));\n console.log();\n\n const files = [\n { path: \"entities.thalo\", content: ENTITIES_THALO.replace(/\\{\\{TIMESTAMP\\}\\}/g, timestamp) },\n {\n path: \"references.thalo\",\n content: REFERENCES_THALO.replace(/\\{\\{TIMESTAMP\\}\\}/g, timestamp),\n },\n ];\n\n let createdCount = 0;\n let warningCount = 0;\n\n for (const file of files) {\n const fullPath = path.join(targetDir, file.path);\n const exists = fs.existsSync(fullPath);\n\n if (exists && !force) {\n console.log(\n `${pc.yellow(\"⚠\")} ${pc.yellow(\"warning:\")} ${file.path} already exists, skipping`,\n );\n warningCount++;\n continue;\n }\n\n if (exists && force) {\n console.log(`${pc.yellow(\"⚠\")} ${pc.yellow(\"overwriting:\")} ${file.path}`);\n }\n\n if (!dryRun) {\n fs.writeFileSync(fullPath, file.content, \"utf-8\");\n }\n\n console.log(`${pc.green(\"✓\")} Created: ${pc.dim(file.path)}`);\n createdCount++;\n }\n\n // Summary\n console.log();\n if (warningCount > 0) {\n console.log(`${pc.yellow(\"Warnings:\")} ${warningCount} file(s) already exist`);\n }\n\n if (dryRun) {\n console.log(pc.dim(\"Run without --dry-run to create files.\"));\n } else if (createdCount > 0) {\n console.log(`${pc.green(\"✓\")} Done! Created ${createdCount} file(s).`);\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Command Definition\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const initCommand: CommandDef = {\n name: \"init\",\n description: \"Initialize THALO with entity definitions and starter references\",\n args: {\n name: \"directory\",\n description: \"Target directory (defaults to current directory)\",\n required: false,\n multiple: false,\n },\n options: {\n \"dry-run\": {\n type: \"boolean\",\n short: \"n\",\n description: \"Show what would be created without making changes\",\n default: false,\n },\n force: {\n type: \"boolean\",\n short: \"f\",\n description: \"Overwrite existing files\",\n default: false,\n },\n },\n action: initAction,\n};\n"],"mappings":";;;;;AASA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CvB,MAAM,mBAAmB;;;;;;;;;;;;;AAkBzB,SAAS,WAAW,KAA2B;CAC7C,MAAM,EAAE,SAAS,SAAS;CAG1B,MAAM,YAAY,KAAK,SAAS,IAAI,KAAK,QAAQ,KAAK,GAAG,GAAG,QAAQ,KAAK;CAIzE,MAAM,6BADM,IAAI,MAAM,EACA,aAAa,CAAC,MAAM,GAAG,GAAG,GAAG;CAEnD,MAAM,SAAS,QAAQ;CACvB,MAAM,QAAQ,QAAQ;AAEtB,KAAI,QAAQ;AACV,UAAQ,IAAI,GAAG,IAAI,0CAA0C,CAAC;AAC9D,UAAQ,KAAK;;AAGf,SAAQ,IAAI,GAAG,KAAK,wBAAwB,CAAC;AAC7C,SAAQ,KAAK;CAEb,MAAM,QAAQ,CACZ;EAAE,MAAM;EAAkB,SAAS,eAAe,QAAQ,sBAAsB,UAAU;EAAE,EAC5F;EACE,MAAM;EACN,SAAS,iBAAiB,QAAQ,sBAAsB,UAAU;EACnE,CACF;CAED,IAAI,eAAe;CACnB,IAAI,eAAe;AAEnB,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAW,KAAK,KAAK,WAAW,KAAK,KAAK;EAChD,MAAM,SAAS,GAAG,WAAW,SAAS;AAEtC,MAAI,UAAU,CAAC,OAAO;AACpB,WAAQ,IACN,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,GAAG,OAAO,WAAW,CAAC,GAAG,KAAK,KAAK,2BACzD;AACD;AACA;;AAGF,MAAI,UAAU,MACZ,SAAQ,IAAI,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,GAAG,OAAO,eAAe,CAAC,GAAG,KAAK,OAAO;AAG5E,MAAI,CAAC,OACH,IAAG,cAAc,UAAU,KAAK,SAAS,QAAQ;AAGnD,UAAQ,IAAI,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,GAAG,IAAI,KAAK,KAAK,GAAG;AAC7D;;AAIF,SAAQ,KAAK;AACb,KAAI,eAAe,EACjB,SAAQ,IAAI,GAAG,GAAG,OAAO,YAAY,CAAC,GAAG,aAAa,wBAAwB;AAGhF,KAAI,OACF,SAAQ,IAAI,GAAG,IAAI,yCAAyC,CAAC;UACpD,eAAe,EACxB,SAAQ,IAAI,GAAG,GAAG,MAAM,IAAI,CAAC,iBAAiB,aAAa,WAAW;;AAQ1E,MAAaA,cAA0B;CACrC,MAAM;CACN,aAAa;CACb,MAAM;EACJ,MAAM;EACN,aAAa;EACb,UAAU;EACV,UAAU;EACX;CACD,SAAS;EACP,WAAW;GACT,MAAM;GACN,OAAO;GACP,aAAa;GACb,SAAS;GACV;EACD,OAAO;GACL,MAAM;GACN,OAAO;GACP,aAAa;GACb,SAAS;GACV;EACF;CACD,QAAQ;CACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rejot-dev/thalo-cli",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,9 +30,9 @@
30
30
  "prettier": "^3.5.3",
31
31
  "vscode-languageserver": "^9.0.1",
32
32
  "web-tree-sitter": "^0.25.0",
33
- "@rejot-dev/thalo": "0.2.4",
34
- "@rejot-dev/thalo-lsp": "0.2.4",
35
- "@rejot-dev/tree-sitter-thalo": "0.2.4"
33
+ "@rejot-dev/thalo": "0.2.5",
34
+ "@rejot-dev/thalo-lsp": "0.2.5",
35
+ "@rejot-dev/tree-sitter-thalo": "0.2.5"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^24",
@@ -40,7 +40,7 @@
40
40
  "tsx": "4.21.0",
41
41
  "typescript": "^5.9.3",
42
42
  "vitest": "^3.2.4",
43
- "@rejot-dev/thalo-prettier": "0.2.4",
43
+ "@rejot-dev/thalo-prettier": "0.2.5",
44
44
  "@rejot-private/typescript-config": "0.0.1"
45
45
  },
46
46
  "scripts": {