diff --git a/apps/docs/dockstat/README.md b/apps/docs/dockstat/README.md index 7546d757..72838972 100644 --- a/apps/docs/dockstat/README.md +++ b/apps/docs/dockstat/README.md @@ -3,7 +3,7 @@ id: 7dddd764-6483-4f84-96a3-988304e772d3 title: DockStat collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: null -updatedAt: 2025-12-17T21:02:58.642Z +updatedAt: 2025-12-29T20:53:33.126Z urlId: zqa4IyZtl0 --- diff --git a/apps/docs/dockstat/api-reference/README.md b/apps/docs/dockstat/api-reference/README.md index bf16cbb6..1972f345 100644 --- a/apps/docs/dockstat/api-reference/README.md +++ b/apps/docs/dockstat/api-reference/README.md @@ -3,7 +3,7 @@ id: b174143d-f906-4f8d-8cb5-9fc96512e575 title: API Reference collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: 7dddd764-6483-4f84-96a3-988304e772d3 -updatedAt: 2025-12-16T19:16:50.491Z +updatedAt: 2025-12-29T20:53:27.622Z urlId: gVYlljv3Fs --- diff --git a/apps/docs/dockstat/api-reference/frontend-plugin-api-(plugins-frontend)/README.md b/apps/docs/dockstat/api-reference/frontend-plugin-api-(plugins-frontend)/README.md index 4ceb47c7..5821bde6 100644 --- a/apps/docs/dockstat/api-reference/frontend-plugin-api-(plugins-frontend)/README.md +++ b/apps/docs/dockstat/api-reference/frontend-plugin-api-(plugins-frontend)/README.md @@ -3,7 +3,7 @@ id: 560ed81b-f22c-4a72-ba1d-650d377e885b title: Frontend Plugin API (plugins/frontend) collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: b174143d-f906-4f8d-8cb5-9fc96512e575 -updatedAt: 2025-12-23T10:10:53.062Z +updatedAt: 2025-12-29T20:53:27.992Z urlId: mok9JVXj9w --- diff --git a/apps/docs/dockstat/apps-overview/README.md b/apps/docs/dockstat/apps-overview/README.md index 8290019e..d0076e56 100644 --- a/apps/docs/dockstat/apps-overview/README.md +++ b/apps/docs/dockstat/apps-overview/README.md @@ -3,7 +3,7 @@ id: fb89c77f-9f0a-497a-bb24-c41d21b37478 title: Apps overview collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: 7dddd764-6483-4f84-96a3-988304e772d3 -updatedAt: 2025-12-17T09:47:18.062Z +updatedAt: 2025-12-29T20:53:32.794Z urlId: YM2LlgAuWf --- diff --git a/apps/docs/dockstat/architecture/README.md b/apps/docs/dockstat/architecture/README.md index 46f8acf5..48fbadf2 100644 --- a/apps/docs/dockstat/architecture/README.md +++ b/apps/docs/dockstat/architecture/README.md @@ -3,7 +3,7 @@ id: d56ca448-563a-4206-9585-c45f8f6be5cf title: Architecture collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: 7dddd764-6483-4f84-96a3-988304e772d3 -updatedAt: 2025-12-16T19:17:04.228Z +updatedAt: 2025-12-29T20:53:27.304Z urlId: g3eBa2Z8rL --- diff --git a/apps/docs/dockstat/configuration/README.md b/apps/docs/dockstat/configuration/README.md index 1b63b32c..3eb66c5a 100644 --- a/apps/docs/dockstat/configuration/README.md +++ b/apps/docs/dockstat/configuration/README.md @@ -3,7 +3,7 @@ id: dec1cb2c-9a13-4e67-a31c-d3a685391208 title: Configuration collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: 7dddd764-6483-4f84-96a3-988304e772d3 -updatedAt: 2025-12-17T09:46:31.595Z +updatedAt: 2025-12-29T20:53:31.749Z urlId: 3dLW6L8pzR --- diff --git a/apps/docs/dockstat/integration-guide/README.md b/apps/docs/dockstat/integration-guide/README.md index 70ae4bb8..e218f579 100644 --- a/apps/docs/dockstat/integration-guide/README.md +++ b/apps/docs/dockstat/integration-guide/README.md @@ -3,7 +3,7 @@ id: e4e04545-fd9f-4fbf-becb-94da81f48bc5 title: Integration guide collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: 7dddd764-6483-4f84-96a3-988304e772d3 -updatedAt: 2025-12-17T09:45:45.019Z +updatedAt: 2025-12-29T20:53:32.118Z urlId: SWA5Nd4lzW --- diff --git a/apps/docs/dockstat/packages/@dockstat-db/README.md b/apps/docs/dockstat/packages/@dockstat-db/README.md index 300245d7..a9afa67d 100644 --- a/apps/docs/dockstat/packages/@dockstat-db/README.md +++ b/apps/docs/dockstat/packages/@dockstat-db/README.md @@ -3,7 +3,7 @@ id: 5176f3ba-1242-4c85-8290-491dcc0f9963 title: "@dockstat/db" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: bbcefaa2-6bd4-46e8-ae4b-a6b823593e67 -updatedAt: 2025-12-17T09:12:31.841Z +updatedAt: 2025-12-29T20:53:28.718Z urlId: LgnEA0nOUp --- diff --git a/apps/docs/dockstat/packages/@dockstat-docker-client/README.md b/apps/docs/dockstat/packages/@dockstat-docker-client/README.md index 55197484..bd8862d4 100644 --- a/apps/docs/dockstat/packages/@dockstat-docker-client/README.md +++ b/apps/docs/dockstat/packages/@dockstat-docker-client/README.md @@ -3,7 +3,7 @@ id: ef12194c-404e-4bcd-a5b0-31aaf7b1b798 title: "@dockstat/docker-client" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: bbcefaa2-6bd4-46e8-ae4b-a6b823593e67 -updatedAt: 2025-12-17T09:16:08.678Z +updatedAt: 2025-12-29T20:53:29.086Z urlId: X0z5b9Ra01 --- diff --git a/apps/docs/dockstat/packages/@dockstat-logger/README.md b/apps/docs/dockstat/packages/@dockstat-logger/README.md index 0022d5d9..50940d94 100644 --- a/apps/docs/dockstat/packages/@dockstat-logger/README.md +++ b/apps/docs/dockstat/packages/@dockstat-logger/README.md @@ -3,7 +3,7 @@ id: e913e6bd-3f7c-485f-812d-3e626b4f6b5b title: "@dockstat/logger" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: bbcefaa2-6bd4-46e8-ae4b-a6b823593e67 -updatedAt: 2025-12-17T09:49:02.729Z +updatedAt: 2025-12-29T20:53:29.526Z urlId: zb1s366Lti --- diff --git a/apps/docs/dockstat/packages/@dockstat-plugin-handler/README.md b/apps/docs/dockstat/packages/@dockstat-plugin-handler/README.md index b4b11830..9e119960 100644 --- a/apps/docs/dockstat/packages/@dockstat-plugin-handler/README.md +++ b/apps/docs/dockstat/packages/@dockstat-plugin-handler/README.md @@ -3,7 +3,7 @@ id: eadaaa93-6c65-4207-a4ac-9b19afc8f2a5 title: "@dockstat/plugin-handler" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: bbcefaa2-6bd4-46e8-ae4b-a6b823593e67 -updatedAt: 2025-12-16T19:04:24.453Z +updatedAt: 2025-12-29T20:53:29.838Z urlId: pXHTTOpluB --- diff --git a/apps/docs/dockstat/packages/@dockstat-sqlite-wrapper/README.md b/apps/docs/dockstat/packages/@dockstat-sqlite-wrapper/README.md index c3028290..950ae682 100644 --- a/apps/docs/dockstat/packages/@dockstat-sqlite-wrapper/README.md +++ b/apps/docs/dockstat/packages/@dockstat-sqlite-wrapper/README.md @@ -3,7 +3,7 @@ id: f543683b-68be-431f-a6d5-7b4012b1345a title: "@dockstat/sqlite-wrapper" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: bbcefaa2-6bd4-46e8-ae4b-a6b823593e67 -updatedAt: 2025-12-17T09:19:53.239Z +updatedAt: 2025-12-29T20:53:28.395Z urlId: vCSP0qqnqI --- diff --git a/apps/docs/dockstat/packages/@dockstat-typings/README.md b/apps/docs/dockstat/packages/@dockstat-typings/README.md index 84975fc2..f46a346e 100644 --- a/apps/docs/dockstat/packages/@dockstat-typings/README.md +++ b/apps/docs/dockstat/packages/@dockstat-typings/README.md @@ -3,7 +3,7 @@ id: ecb9e07b-37e7-430a-b3fc-eb51515ab9ac title: "@dockstat/typings" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: bbcefaa2-6bd4-46e8-ae4b-a6b823593e67 -updatedAt: 2025-12-16T19:05:51.049Z +updatedAt: 2025-12-29T20:53:30.259Z urlId: 7Ae5a9YIKb --- diff --git a/apps/docs/dockstat/packages/@dockstat-ui/README.md b/apps/docs/dockstat/packages/@dockstat-ui/README.md index 620f3cdb..c323371f 100644 --- a/apps/docs/dockstat/packages/@dockstat-ui/README.md +++ b/apps/docs/dockstat/packages/@dockstat-ui/README.md @@ -3,7 +3,7 @@ id: a04555b5-b827-4441-ae20-9cad1a2be714 title: "@dockstat/ui" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: bbcefaa2-6bd4-46e8-ae4b-a6b823593e67 -updatedAt: 2025-12-17T09:23:29.497Z +updatedAt: 2025-12-29T20:53:30.738Z urlId: NXWduCaEB3 --- diff --git a/apps/docs/dockstat/packages/@dockstat-utils/README.md b/apps/docs/dockstat/packages/@dockstat-utils/README.md index 7dbfc868..6c729226 100644 --- a/apps/docs/dockstat/packages/@dockstat-utils/README.md +++ b/apps/docs/dockstat/packages/@dockstat-utils/README.md @@ -3,7 +3,7 @@ id: d3039895-f53c-46ab-89ce-de0ad22ce03c title: "@dockstat/utils" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: bbcefaa2-6bd4-46e8-ae4b-a6b823593e67 -updatedAt: 2025-12-17T09:38:34.988Z +updatedAt: 2025-12-29T20:53:31.102Z urlId: dHg9YfruFJ --- diff --git a/apps/docs/dockstat/packages/README.md b/apps/docs/dockstat/packages/README.md index 26bade00..fc96aa65 100644 --- a/apps/docs/dockstat/packages/README.md +++ b/apps/docs/dockstat/packages/README.md @@ -3,7 +3,7 @@ id: bbcefaa2-6bd4-46e8-ae4b-a6b823593e67 title: Packages collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: 7dddd764-6483-4f84-96a3-988304e772d3 -updatedAt: 2025-12-16T19:07:33.253Z +updatedAt: 2025-12-29T20:53:31.495Z urlId: waARCz3AZ0 --- diff --git a/apps/docs/dockstat/troubleshooting/README.md b/apps/docs/dockstat/troubleshooting/README.md index 28b967e9..e3aa6c3c 100644 --- a/apps/docs/dockstat/troubleshooting/README.md +++ b/apps/docs/dockstat/troubleshooting/README.md @@ -3,7 +3,7 @@ id: 88a5f959-3f89-4266-9d8e-eb50193425b0 title: Troubleshooting collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: 7dddd764-6483-4f84-96a3-988304e772d3 -updatedAt: 2025-12-17T09:44:51.395Z +updatedAt: 2025-12-29T20:53:32.430Z urlId: lgGFKJhiDO --- diff --git a/packages/outline-sync/src/index.ts b/packages/outline-sync/src/index.ts index b5865a98..28c26083 100644 --- a/packages/outline-sync/src/index.ts +++ b/packages/outline-sync/src/index.ts @@ -1,182 +1,105 @@ -import { existsSync } from "node:fs" -import { readFile, writeFile } from "node:fs/promises" -import { join } from "node:path" -import { Command } from "commander" -import { OutlineSync } from "./sync" -import type { OutlineConfig } from "./types" - -const program = new Command() - -async function loadConfig(configPath?: string): Promise> { - const defaultPath = join(process.cwd(), "outline-sync.config.json") - const path = configPath || defaultPath - - if (existsSync(path)) { - console.log(`šŸ“ Loading config from ${path}`) - const content = await readFile(path, "utf-8") - return JSON.parse(content) +import fs from 'fs'; +import path from 'path'; + +const fsp = fs.promises; + +const CONFIG_FILENAMES = [ + 'outline.config.js', + 'outline.config.cjs', + 'outline.config.json', + 'outline.config', + '.outlinerc', + 'outline.config.yaml', + 'outline.config.yml', + 'package.json' +]; + +/** + * Search for a configuration file. + * - If process.env.OUTLINE_CONFIG is set, that path is used (resolved relative to cwd if not absolute). + * - Otherwise, walk up parent directories from startDir looking for any of CONFIG_FILENAMES. + * Returns the resolved path or null if not found. + */ +export async function findConfig(startDir?: string): Promise { + const cwd = process.cwd(); + + // Respect explicit environment override first + const envPath = process.env.OUTLINE_CONFIG; + if (envPath) { + const resolved = path.isAbsolute(envPath) ? envPath : path.resolve(cwd, envPath); + try { + await fsp.access(resolved, fs.constants.R_OK); + return resolved; + } catch (err) { + // If the env-provided path doesn't exist, we continue to search as a fallback + // but also surface a helpful error downstream if needed. + } } - return {} -} - -function parseArrayOption(value: string): string[] { - return value - .split(",") - .map((s) => s.trim()) - .filter(Boolean) -} - -async function getConfig( - options: { - url: string - include: string - exclude: string - token?: string - outputDir: string - output: string - config: string - verbose?: boolean - }, - loadConfigFile = true -): Promise { - const fileConfig = loadConfigFile ? await loadConfig(options.config) : {} - - const config: OutlineConfig = { - url: options.url || fileConfig.url || process.env.OUTLINE_URL || "", - token: options.token || fileConfig.token || process.env.OUTLINE_TOKEN || "", - outputDir: - options.output || fileConfig.outputDir || process.env.OUTLINE_OUTPUT_DIR || "./outline-docs", - customPaths: fileConfig.customPaths || {}, - includeCollections: options.include - ? parseArrayOption(options.include) - : fileConfig.includeCollections, - excludeCollections: options.exclude - ? parseArrayOption(options.exclude) - : fileConfig.excludeCollections, - verbose: Boolean(options.verbose), - } + // Start searching from provided startDir or cwd and walk up to the filesystem root + let dir = path.resolve(startDir || cwd); + while (true) { + for (const name of CONFIG_FILENAMES) { + const candidate = path.join(dir, name); + try { + await fsp.access(candidate, fs.constants.R_OK); + return candidate; + } catch (_) { + // not found, continue + } + } - if (!config.url || !config.token) { - console.error("Error: OUTLINE_URL and OUTLINE_TOKEN must be provided") - console.error("Set via:") - console.error(" - Environment variables (OUTLINE_URL, OUTLINE_TOKEN)") - console.error(" - CLI arguments (--url, --token)") - console.error(" - Config file (outline-sync.config.json)") - process.exit(1) + const parent = path.dirname(dir); + if (parent === dir) break; // reached root + dir = parent; } - return config + return null; } -program.name("outline-sync").description("Sync Outline wiki to local folder").version("1.0.0") - -program - .command("sync") - .description("One-time sync from Outline to local") - .option("-u, --url ", "Outline URL") - .option("-t, --token ", "API token") - .option("-o, --output ", "Output directory") - .option("-c, --config ", "Config file path") - .option("-i, --include ", "Comma-separated list of collections to include") - .option("-e, --exclude ", "Comma-separated list of collections to exclude") - .option("-v, --verbose", "Enable debug logging") - .action(async (options) => { - const config = await getConfig(options) - const sync = new OutlineSync(config, { verbose: config.verbose }) - await sync.syncDown() - }) - -program - .command("watch") - .description("Watch for local changes and sync bidirectionally") - .option("-u, --url ", "Outline URL") - .option("-t, --token ", "API token") - .option("-o, --output ", "Output directory") - .option("-c, --config ", "Config file path") - .option("-i, --include ", "Comma-separated list of collections to include") - .option("-e, --exclude ", "Comma-separated list of collections to exclude") - .option("-v, --verbose", "Enable debug logging") - .action(async (options) => { - const config = await getConfig(options) - const sync = new OutlineSync(config, { verbose: config.verbose }) - await sync.watch() - }) - -program - .command("ci") - .description("CI/CD mode: sync both ways") - .option("-u, --url ", "Outline URL") - .option("-t, --token ", "API token") - .option("-o, --output ", "Output directory") - .option("-c, --config ", "Config file path") - .option("-i, --include ", "Comma-separated list of collections to include") - .option("-e, --exclude ", "Comma-separated list of collections to exclude") - .option("-v, --verbose", "Enable debug logging") - .action(async (options) => { - const config = await getConfig(options) - const sync = new OutlineSync(config, { verbose: config.verbose }) - await sync.ciSync() - }) - -program - .command("push") - .description("Push local changes to Outline") - .option("-u, --url ", "Outline URL") - .option("-t, --token ", "API token") - .option("-o, --output ", "Output directory") - .option("-c, --config ", "Config file path") - .option("-i, --include ", "Comma-separated list of collections to include") - .option("-e, --exclude ", "Comma-separated list of collections to exclude") - .option("-v, --verbose", "Enable debug logging") - .action(async (options) => { - const config = await getConfig(options) - const sync = new OutlineSync(config, { verbose: config.verbose }) - await sync.push() - }) +/** + * Load configuration discovered by findConfig. + * - JS/CJS files are required() so they can export functions/objects. + * - JSON and package.json are parsed as JSON. If package.json contains an `outline` key, that is returned. + * - Other files are attempted to be JSON-parsed as a fallback; if parsing fails the raw text is returned. + */ +export async function loadConfig(startDir?: string): Promise { + const configPath = await findConfig(startDir); + if (!configPath) return null; + + const ext = path.extname(configPath).toLowerCase(); + const base = path.basename(configPath).toLowerCase(); + + try { + if (ext === '.js' || ext === '.cjs') { + // Use require so JavaScript config files can export functions/objects. + // Delete from cache to pick up changes when repeatedly run in a long-lived process. + try { + delete require.cache[require.resolve(configPath)]; + } catch (_) {} + // eslint-disable-next-line @typescript-eslint/no-var-requires + const mod = require(configPath); + return mod && mod.__esModule && mod.default ? mod.default : mod; + } -program - .command("init") - .description("Create a sample configuration file") - .action(async () => { - const configPath = join(process.cwd(), "outline-sync.config.json") + const raw = await fsp.readFile(configPath, 'utf8'); - if (existsSync(configPath)) { - console.error("āŒ outline-sync.config.json already exists") - process.exit(1) + if (ext === '.json' || base === 'package.json') { + const parsed = JSON.parse(raw); + if (base === 'package.json') return parsed.outline || parsed; + return parsed; } - const sampleConfig = { - url: "https://your-outline.com", - token: "your_api_token", - outputDir: "./outline-docs", - includeCollections: ["Engineering", "Product"], - excludeCollections: [], - customPaths: { - "example-doc-id": "../../README.md", - "another-doc-id": "custom/path/document.md", - }, + // Fallback: try JSON parse, otherwise return raw text + try { + return JSON.parse(raw); + } catch (_) { + return raw; } + } catch (err) { + // Re-throw with some context + throw new Error(`Failed to load config at ${configPath}: ${err instanceof Error ? err.message : String(err)}`); + } +} - await writeFile(configPath, JSON.stringify(sampleConfig, null, 2), "utf-8") - console.log("āœ… Created outline-sync.config.json") - console.log("\nšŸ“ Edit the file and replace example values with your actual configuration") - }) - -program - .command("verify") - .description("Verify configuration and show resolved custom paths") - .option("-u, --url ", "Outline URL") - .option("-t, --token ", "API token") - .option("-o, --output ", "Output directory") - .option("-c, --config ", "Config file path") - .option("-i, --include ", "Comma-separated list of collections to include") - .option("-e, --exclude ", "Comma-separated list of collections to exclude") - .option("-v, --verbose", "Enable debug logging") - .action(async (options) => { - const config = await getConfig(options) - const sync = new OutlineSync(config, { verbose: config.verbose }) - await sync.verify() - }) - -program.parse() +export default loadConfig; diff --git a/packages/template-renderer/README.md b/packages/template-renderer/README.md index f3864642..ccac700d 100644 --- a/packages/template-renderer/README.md +++ b/packages/template-renderer/README.md @@ -3,7 +3,7 @@ id: 453740d4-b426-423d-98fc-b36f6dff7644 title: "@dockstat/template-renderer" collectionId: b4a5e48f-f103-480b-9f50-8f53f515cab9 parentDocumentId: bbcefaa2-6bd4-46e8-ae4b-a6b823593e67 -updatedAt: 2025-12-23T12:50:44.974Z +updatedAt: 2025-12-24T00:36:09.100Z urlId: 5qbatLB5V0 --- @@ -75,7 +75,7 @@ import { TemplateRenderer, parseTemplate } from "@dockstat/template-renderer" import { useState } from "react" function MyPage() { - const templateYaml = `...` // Your YAML template + const templateYaml = `...` const result = parseTemplate(templateYaml, "yaml") if (!result.success) { @@ -98,7 +98,6 @@ function MyPage() { ### Using the Builder API ```typescript - import { template, widgets, @@ -210,7 +209,6 @@ All widgets from `@dockstat/ui` are available: Bind widget props to state or data using the `bindings` property: ```yaml - widgets: - type: text props: @@ -234,7 +232,6 @@ widgets: Use the `condition` property to conditionally render widgets: ```yaml - widgets: - type: badge props: @@ -253,7 +250,6 @@ widgets: Render widgets for each item in an array: ```yaml - widgets: - type: card props: @@ -276,7 +272,6 @@ widgets: Use templates in your DockStat plugins: ```typescript - import type { PluginFrontendConfig } from "@dockstat/template-renderer" const frontendConfig: PluginFrontendConfig = {