md-task-viewer 0.1.5 → 0.1.7
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 +1 -1
- package/dist/cli.js +27 -7
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/index-BfBV_hRv.css +1 -0
- package/dist/client/assets/index-Bl8f2bX8.js +77 -0
- package/dist/client/index.html +2 -2
- package/dist/server.js +27 -7
- package/dist/server.js.map +1 -1
- package/package.json +15 -12
- package/dist/client/assets/index-BcWwd56a.js +0 -59
- package/dist/client/assets/index-LYvJrXuE.css +0 -1
package/dist/client/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Markdown Task Viewer</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-Bl8f2bX8.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BfBV_hRv.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
package/dist/server.js
CHANGED
|
@@ -168,12 +168,22 @@ async function reconcileOrder(rootDir, taskPaths) {
|
|
|
168
168
|
const config = await readConfig(rootDir);
|
|
169
169
|
const order = config.order;
|
|
170
170
|
const known = new Set(taskPaths);
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
const orderSet = new Set(order);
|
|
172
|
+
const newItems = taskPaths.filter((p) => !orderSet.has(p));
|
|
173
|
+
const removedCount = order.reduce((count, item) => known.has(item) ? count : count + 1, 0);
|
|
174
|
+
const canReplace = newItems.length > 0 && newItems.length === removedCount;
|
|
175
|
+
const nextOrder = [];
|
|
176
|
+
let newItemCursor = 0;
|
|
177
|
+
for (let i = 0; i < order.length; i++) {
|
|
178
|
+
if (known.has(order[i])) {
|
|
179
|
+
nextOrder.push(order[i]);
|
|
180
|
+
} else if (canReplace && newItemCursor < newItems.length) {
|
|
181
|
+
nextOrder.push(newItems[newItemCursor++]);
|
|
175
182
|
}
|
|
176
183
|
}
|
|
184
|
+
while (newItemCursor < newItems.length) {
|
|
185
|
+
nextOrder.push(newItems[newItemCursor++]);
|
|
186
|
+
}
|
|
177
187
|
const changed = nextOrder.length !== order.length || nextOrder.some((item, index) => item !== order[index]);
|
|
178
188
|
return { order: nextOrder, changed };
|
|
179
189
|
}
|
|
@@ -350,9 +360,19 @@ async function updateTask(rootDir, currentPath, input) {
|
|
|
350
360
|
await fs.mkdir(path.dirname(absoluteNextPath), { recursive: true });
|
|
351
361
|
await fs.rename(absoluteCurrentPath, absoluteNextPath);
|
|
352
362
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
363
|
+
if (nextPath !== normalizedCurrentPath) {
|
|
364
|
+
const config = await readConfig(rootDir);
|
|
365
|
+
const filteredOrder = config.order.filter((item) => item !== nextPath);
|
|
366
|
+
const index = filteredOrder.indexOf(normalizedCurrentPath);
|
|
367
|
+
let updatedOrder;
|
|
368
|
+
if (index === -1) {
|
|
369
|
+
updatedOrder = [...filteredOrder, nextPath];
|
|
370
|
+
} else {
|
|
371
|
+
updatedOrder = [...filteredOrder];
|
|
372
|
+
updatedOrder[index] = nextPath;
|
|
373
|
+
}
|
|
374
|
+
await saveOrder(rootDir, updatedOrder);
|
|
375
|
+
}
|
|
356
376
|
return parseTask(rootDir, nextPath);
|
|
357
377
|
}
|
|
358
378
|
async function deleteTask(rootDir, relativePath) {
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts","../src/taskStore.ts","../src/types.ts","../src/slugify.ts","../src/commandExecutor.ts"],"sourcesContent":["import Fastify, { type FastifyInstance } from \"fastify\";\nimport fastifyStatic from \"@fastify/static\";\nimport chokidar from \"chokidar\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n ConflictError,\n ValidationError,\n createTask,\n deleteTask,\n listTasks,\n parseOrderPayload,\n parseTask,\n patchTaskFields,\n readConfig,\n saveConfig,\n saveOrder,\n updateTask\n} from \"./taskStore.js\";\nimport type { CommandStep } from \"./types.js\";\nimport { executeCommandPipeline } from \"./commandExecutor.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface CreateServerOptions {\n rootDir: string;\n clientDir?: string | null;\n}\n\nfunction resolveClientDir(explicitClientDir?: string | null): string | null {\n if (explicitClientDir === null) {\n return null;\n }\n if (explicitClientDir) {\n return explicitClientDir;\n }\n return path.resolve(__dirname, \"client\");\n}\n\nfunction sendJsonError(reply: { code: (statusCode: number) => { send: (payload: unknown) => void } }, error: unknown): void {\n if (error instanceof ValidationError) {\n reply.code(400).send({ error: error.message });\n return;\n }\n if (error instanceof ConflictError) {\n reply.code(409).send({ error: error.message });\n return;\n }\n reply.code(500).send({ error: error instanceof Error ? error.message : \"Internal server error\" });\n}\n\nexport async function createServer(options: CreateServerOptions): Promise<FastifyInstance> {\n const app = Fastify({ logger: false });\n const listeners = new Set<{ send: (payload: string) => void; close: () => void }>();\n const clientDir = resolveClientDir(options.clientDir);\n\n app.addHook(\"onClose\", async () => {\n for (const listener of listeners) {\n listener.close();\n }\n });\n\n app.get(\"/api/tasks\", async () => listTasks(options.rootDir));\n\n app.post(\"/api/tasks\", async (request, reply) => {\n try {\n const task = await createTask(options.rootDir, (request.body ?? {}) as never);\n return reply.code(201).send(task);\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.patch(\"/api/tasks/*\", async (request, reply) => {\n const currentPath = decodeURIComponent((request.params as { \"*\": string })[\"*\"] ?? \"\");\n try {\n const task = await updateTask(options.rootDir, currentPath, (request.body ?? {}) as never);\n return reply.send(task);\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.delete(\"/api/tasks/*\", async (request, reply) => {\n const currentPath = decodeURIComponent((request.params as { \"*\": string })[\"*\"] ?? \"\");\n try {\n await deleteTask(options.rootDir, currentPath);\n return reply.code(204).send();\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.patch(\"/api/task-fields/*\", async (request, reply) => {\n const currentPath = decodeURIComponent((request.params as { \"*\": string })[\"*\"] ?? \"\");\n try {\n const task = await patchTaskFields(options.rootDir, currentPath, (request.body ?? {}) as never);\n return reply.send(task);\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.put(\"/api/order\", async (request, reply) => {\n try {\n const order = parseOrderPayload((request.body as { order?: unknown } | null)?.order ?? []);\n await saveOrder(options.rootDir, order);\n return reply.code(204).send();\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.get(\"/api/config\", async () => {\n try {\n return await readConfig(options.rootDir);\n } catch (error) {\n return { version: 1, taskDirs: [\".\"], order: [] };\n }\n });\n\n app.put(\"/api/config\", async (request, reply) => {\n try {\n const body = request.body as { taskDirs?: unknown; ignorePaths?: unknown; commands?: unknown } | null;\n const taskDirs = body?.taskDirs;\n if (!Array.isArray(taskDirs) || taskDirs.some((item) => typeof item !== \"string\")) {\n throw new ValidationError(\"taskDirs must be an array of strings.\");\n }\n let ignorePaths: string[] | undefined;\n if (body?.ignorePaths !== undefined) {\n if (!Array.isArray(body.ignorePaths) || body.ignorePaths.some((item) => typeof item !== \"string\")) {\n throw new ValidationError(\"ignorePaths must be an array of strings.\");\n }\n ignorePaths = body.ignorePaths as string[];\n }\n let commands: CommandStep[] | undefined;\n if (body?.commands !== undefined) {\n if (!Array.isArray(body.commands)) {\n throw new ValidationError(\"commands must be an array.\");\n }\n commands = body.commands as CommandStep[];\n }\n const config = await saveConfig(options.rootDir, taskDirs as string[], ignorePaths, commands);\n return reply.send(config);\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.post(\"/api/execute\", async (request, reply) => {\n try {\n const body = request.body as { taskPath?: string; commands?: CommandStep[] } | null;\n const taskPath = body?.taskPath;\n if (!taskPath || typeof taskPath !== \"string\") {\n throw new ValidationError(\"taskPath is required.\");\n }\n\n let task;\n try {\n task = await parseTask(options.rootDir, taskPath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n return reply.code(404).send({ error: \"Task not found.\" });\n }\n throw error;\n }\n\n // Resolve commands: request body > task extraFrontmatter > global config\n let commands = body?.commands;\n if (!commands || commands.length === 0) {\n const taskCommands = task.extraFrontmatter.commands;\n if (Array.isArray(taskCommands) && taskCommands.length > 0) {\n commands = taskCommands as CommandStep[];\n }\n }\n if (!commands || commands.length === 0) {\n const config = await readConfig(options.rootDir);\n commands = config.commands;\n }\n if (!commands || commands.length === 0) {\n throw new ValidationError(\"No commands configured.\");\n }\n\n const result = await executeCommandPipeline(options.rootDir, commands, task);\n return reply.send(result);\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.get(\"/api/events\", async (_request, reply) => {\n reply.raw.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\"\n });\n reply.raw.write(\"\\n\");\n\n const listener = {\n send(payload: string) {\n reply.raw.write(`data: ${payload}\\n\\n`);\n },\n close() {\n reply.raw.end();\n }\n };\n\n listeners.add(listener);\n reply.raw.on(\"close\", () => {\n listeners.delete(listener);\n });\n\n return reply.hijack();\n });\n\n const watcher = chokidar.watch(options.rootDir, {\n ignoreInitial: true,\n ignored: (watchPath) => watchPath.includes(`${path.sep}.git`) || watchPath.includes(`${path.sep}node_modules`)\n });\n\n watcher.on(\"all\", (eventName, changedPath) => {\n const isMarkdown = changedPath.endsWith(\".md\") || changedPath.endsWith(\".markdown\");\n const isConfigFile = path.basename(changedPath) === \".md-task-viewer.json\";\n if (!isMarkdown && !isConfigFile) {\n return;\n }\n\n const payload = JSON.stringify({\n type: \"tasks-changed\",\n eventName,\n path: path.relative(options.rootDir, changedPath)\n });\n\n for (const listener of listeners) {\n listener.send(payload);\n }\n });\n\n app.addHook(\"onClose\", async () => {\n await watcher.close();\n });\n\n if (clientDir) {\n await app.register(fastifyStatic, {\n root: clientDir,\n prefix: \"/\"\n });\n\n app.setNotFoundHandler(async (request, reply) => {\n if (request.raw.url?.startsWith(\"/api/\")) {\n return reply.code(404).send({ error: \"Not found\" });\n }\n return reply.sendFile(\"index.html\");\n });\n }\n\n return app;\n}\n","import matter from \"gray-matter\";\nimport picomatch from \"picomatch\";\nimport path from \"node:path\";\nimport { promises as fs } from \"node:fs\";\nimport {\n CONFIG_FILE_NAME,\n type CommandStep,\n type ConfigFile,\n type CreateTaskInput,\n type PatchTaskFieldsInput,\n type TaskFrontmatter,\n type TaskListResponse,\n type TaskParseError,\n type TaskPriority,\n type TaskRecord,\n type TaskStatus,\n type UpdateTaskInput\n} from \"./types.js\";\nimport { slugify } from \"./slugify.js\";\n\nconst MARKDOWN_EXTENSIONS = new Set([\".md\", \".markdown\"]);\nconst REQUIRED_PRIORITY: TaskPriority[] = [\"MUST\", \"WANT\"];\nconst REQUIRED_STATUS: TaskStatus[] = [\"TODO\", \"WIP\", \"DONE\"];\n\nexport class ConflictError extends Error {}\nexport class ValidationError extends Error {}\n\nfunction toPosixPath(filePath: string): string {\n return filePath.split(path.sep).join(\"/\");\n}\n\nfunction normalizeRelativePath(candidate: string): string {\n const normalized = toPosixPath(path.posix.normalize(candidate.trim()));\n if (!normalized || normalized === \".\" || normalized.startsWith(\"../\") || normalized.includes(\"/../\")) {\n throw new ValidationError(\"Path must stay within the workspace root.\");\n }\n\n return normalized.replace(/^\\.\\/+/, \"\");\n}\n\nfunction ensureMarkdownExtension(filePath: string): string {\n return path.posix.extname(filePath) ? filePath : `${filePath}.md`;\n}\n\nfunction asUtcISOString(date: Date): string {\n return date.toISOString();\n}\n\nfunction buildDefaults(filePath: string, stats: { birthtime: Date; mtime: Date }): TaskFrontmatter {\n const basename = path.basename(filePath, path.extname(filePath));\n const title = basename.replace(/[-_]+/g, \" \").replace(/\\b\\w/g, (char) => char.toUpperCase());\n\n return {\n title,\n priority: \"WANT\",\n status: \"TODO\",\n createdAt: asUtcISOString(stats.birthtime),\n updatedAt: asUtcISOString(stats.mtime)\n };\n}\n\nfunction splitFrontmatter(data: Record<string, unknown>, statsDefaults: TaskFrontmatter): {\n frontmatter: TaskFrontmatter;\n extraFrontmatter: Record<string, unknown>;\n normalized: boolean;\n} {\n const extraFrontmatter: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(data)) {\n if (![\"title\", \"priority\", \"status\", \"createdAt\", \"updatedAt\"].includes(key)) {\n extraFrontmatter[key] = value;\n }\n }\n\n const title = typeof data.title === \"string\" && data.title.trim() ? data.title : statsDefaults.title;\n const priority = REQUIRED_PRIORITY.includes(data.priority as TaskPriority)\n ? (data.priority as TaskPriority)\n : statsDefaults.priority;\n const status = REQUIRED_STATUS.includes(data.status as TaskStatus)\n ? (data.status as TaskStatus)\n : statsDefaults.status;\n const createdAt =\n typeof data.createdAt === \"string\" && !Number.isNaN(Date.parse(data.createdAt))\n ? new Date(data.createdAt).toISOString()\n : statsDefaults.createdAt;\n const updatedAt =\n typeof data.updatedAt === \"string\" && !Number.isNaN(Date.parse(data.updatedAt))\n ? new Date(data.updatedAt).toISOString()\n : statsDefaults.updatedAt;\n\n const normalized =\n title !== data.title ||\n priority !== data.priority ||\n status !== data.status ||\n createdAt !== data.createdAt ||\n updatedAt !== data.updatedAt;\n\n return {\n frontmatter: { title, priority, status, createdAt, updatedAt },\n extraFrontmatter,\n normalized\n };\n}\n\nexport function serializeTask(record: TaskRecord): string {\n const data = {\n ...record.extraFrontmatter,\n title: record.frontmatter.title,\n priority: record.frontmatter.priority,\n status: record.frontmatter.status,\n createdAt: record.frontmatter.createdAt,\n updatedAt: record.frontmatter.updatedAt\n };\n\n return matter.stringify(record.content, data);\n}\n\nasync function readDirectoryRecursive(rootDir: string, currentDir: string, results: string[]): Promise<void> {\n const entries = await fs.readdir(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.name === \".git\" || entry.name === \"node_modules\") {\n continue;\n }\n\n const absolutePath = path.join(currentDir, entry.name);\n if (entry.isDirectory()) {\n await readDirectoryRecursive(rootDir, absolutePath, results);\n continue;\n }\n\n if (entry.name === CONFIG_FILE_NAME) {\n continue;\n }\n\n if (!MARKDOWN_EXTENSIONS.has(path.extname(entry.name).toLowerCase())) {\n continue;\n }\n\n results.push(toPosixPath(path.relative(rootDir, absolutePath)));\n }\n}\n\nasync function listMarkdownFiles(rootDir: string, taskDirs: string[], ignorePaths: string[]): Promise<string[]> {\n const results: string[] = [];\n const seen = new Set<string>();\n\n const isIgnored = ignorePaths.length > 0 ? picomatch(ignorePaths) : null;\n\n for (const taskDir of taskDirs) {\n const scanDir = path.resolve(rootDir, taskDir);\n try {\n await fs.access(scanDir);\n } catch {\n continue;\n }\n const dirResults: string[] = [];\n await readDirectoryRecursive(rootDir, scanDir, dirResults);\n for (const filePath of dirResults) {\n if (!seen.has(filePath)) {\n seen.add(filePath);\n if (isIgnored && isIgnored(filePath)) {\n continue;\n }\n results.push(filePath);\n }\n }\n }\n\n return results.sort();\n}\n\nexport async function parseTask(rootDir: string, relativePath: string): Promise<TaskRecord> {\n const absolutePath = path.join(rootDir, relativePath);\n const raw = await fs.readFile(absolutePath, \"utf8\");\n const stats = await fs.stat(absolutePath);\n const parsed = matter(raw);\n const defaults = buildDefaults(relativePath, stats);\n const { frontmatter, extraFrontmatter, normalized } = splitFrontmatter(parsed.data, defaults);\n\n return {\n path: toPosixPath(relativePath),\n content: parsed.content,\n frontmatter,\n extraFrontmatter,\n raw,\n normalized\n };\n}\n\nexport async function readConfig(rootDir: string): Promise<ConfigFile> {\n const configFilePath = path.join(rootDir, CONFIG_FILE_NAME);\n\n try {\n const raw = await fs.readFile(configFilePath, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<ConfigFile>;\n const taskDirs = Array.isArray(parsed.taskDirs)\n ? parsed.taskDirs.filter((item): item is string => typeof item === \"string\")\n : [\".\"];\n const ignorePaths = Array.isArray(parsed.ignorePaths)\n ? parsed.ignorePaths.filter((item): item is string => typeof item === \"string\")\n : [];\n const order = Array.isArray(parsed.order)\n ? parsed.order.filter((item): item is string => typeof item === \"string\")\n : [];\n const commands = Array.isArray(parsed.commands)\n ? (parsed.commands as CommandStep[])\n : undefined;\n return { version: parsed.version ?? 1, taskDirs, ignorePaths, order, commands };\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code !== \"ENOENT\") {\n throw error;\n }\n return { version: 1, taskDirs: [\".\"], ignorePaths: [], order: [] };\n }\n}\n\nasync function reconcileOrder(rootDir: string, taskPaths: string[]): Promise<{ order: string[]; changed: boolean }> {\n const config = await readConfig(rootDir);\n const order = config.order;\n\n const known = new Set(taskPaths);\n const nextOrder = order.filter((item) => known.has(item));\n for (const taskPath of taskPaths) {\n if (!nextOrder.includes(taskPath)) {\n nextOrder.push(taskPath);\n }\n }\n\n const changed = nextOrder.length !== order.length || nextOrder.some((item, index) => item !== order[index]);\n return { order: nextOrder, changed };\n}\n\nexport async function saveOrder(rootDir: string, order: string[]): Promise<void> {\n const normalized = Array.from(\n new Set(\n order.map((item) => ensureMarkdownExtension(normalizeRelativePath(item)))\n )\n );\n const existing = await readConfig(rootDir);\n const payload: ConfigFile = { version: 1, taskDirs: existing.taskDirs, ignorePaths: existing.ignorePaths, order: normalized, commands: existing.commands };\n await fs.writeFile(path.join(rootDir, CONFIG_FILE_NAME), `${JSON.stringify(payload, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function saveConfig(rootDir: string, taskDirs: string[], ignorePaths?: string[], commands?: CommandStep[]): Promise<ConfigFile> {\n const validated = taskDirs.map((dir) => {\n const normalized = dir.trim().replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\") || \".\";\n if (normalized.startsWith(\"../\") || normalized.includes(\"/../\")) {\n throw new ValidationError(\"taskDirs must stay within the workspace root.\");\n }\n return normalized;\n });\n if (validated.length === 0) {\n throw new ValidationError(\"taskDirs must contain at least one directory.\");\n }\n const existing = await readConfig(rootDir);\n const validatedIgnorePaths = ignorePaths ?? existing.ignorePaths;\n const validatedCommands = commands !== undefined ? commands : existing.commands;\n const payload: ConfigFile = { version: 1, taskDirs: validated, ignorePaths: validatedIgnorePaths, order: existing.order, commands: validatedCommands };\n await fs.writeFile(path.join(rootDir, CONFIG_FILE_NAME), `${JSON.stringify(payload, null, 2)}\\n`, \"utf8\");\n return payload;\n}\n\nexport async function listTasks(rootDir: string): Promise<TaskListResponse> {\n const config = await readConfig(rootDir);\n const files = await listMarkdownFiles(rootDir, config.taskDirs, config.ignorePaths);\n const errors: TaskParseError[] = [];\n const tasks = await Promise.all(\n files.map(async (relativePath) => {\n try {\n return await parseTask(rootDir, relativePath);\n } catch (error) {\n errors.push({\n path: relativePath,\n message: error instanceof Error ? error.message : \"Unknown parse error\"\n });\n return null;\n }\n })\n );\n\n const taskRecords = tasks.filter((task): task is TaskRecord => task !== null);\n const { order, changed } = await reconcileOrder(\n rootDir,\n taskRecords.map((task) => task.path)\n );\n\n if (changed) {\n await saveOrder(rootDir, order);\n }\n\n const orderIndex = new Map(order.map((item, index) => [item, index]));\n taskRecords.sort((left, right) => {\n const leftIndex = orderIndex.get(left.path) ?? Number.MAX_SAFE_INTEGER;\n const rightIndex = orderIndex.get(right.path) ?? Number.MAX_SAFE_INTEGER;\n return leftIndex - rightIndex || left.path.localeCompare(right.path);\n });\n\n return { tasks: taskRecords, errors };\n}\n\nasync function ensureDirectoryForFile(rootDir: string, relativeFilePath: string): Promise<string> {\n const normalized = ensureMarkdownExtension(normalizeRelativePath(relativeFilePath));\n const absolutePath = path.join(rootDir, normalized);\n const directory = path.dirname(absolutePath);\n await fs.mkdir(directory, { recursive: true });\n return normalized;\n}\n\nasync function nextAvailablePath(rootDir: string, directory: string, title: string): Promise<string> {\n const safeDirectory = directory ? normalizeRelativePath(directory) : \"\";\n const slug = slugify(title);\n const base = safeDirectory ? `${safeDirectory}/${slug}` : slug;\n\n let attempt = 0;\n while (true) {\n const candidate = ensureMarkdownExtension(attempt === 0 ? base : `${base}-${attempt + 1}`);\n try {\n await fs.access(path.join(rootDir, candidate));\n attempt += 1;\n } catch {\n return candidate;\n }\n }\n}\n\nexport async function createTask(rootDir: string, input: CreateTaskInput): Promise<TaskRecord> {\n if (!input.title.trim()) {\n throw new ValidationError(\"Title is required.\");\n }\n\n const now = asUtcISOString(new Date());\n const relativePath = input.path?.trim()\n ? await ensureDirectoryForFile(rootDir, input.path)\n : await nextAvailablePath(rootDir, input.directory ?? \"\", input.title);\n const absolutePath = path.join(rootDir, relativePath);\n\n try {\n await fs.access(absolutePath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n // The target path is available.\n } else if (maybeError.code) {\n throw error;\n } else {\n throw new ValidationError(\"A task already exists at that path.\");\n }\n }\n\n const record: TaskRecord = {\n path: relativePath,\n content: input.content ?? \"\",\n raw: \"\",\n normalized: false,\n extraFrontmatter: input.extraFrontmatter ?? {},\n frontmatter: {\n title: input.title.trim(),\n priority: input.priority ?? \"MUST\",\n status: input.status ?? \"TODO\",\n createdAt: now,\n updatedAt: now\n }\n };\n\n await fs.mkdir(path.dirname(absolutePath), { recursive: true });\n await fs.writeFile(absolutePath, serializeTask(record), \"utf8\");\n\n const current = await listTasks(rootDir);\n await saveOrder(rootDir, current.tasks.map((task) => task.path).concat(relativePath));\n return parseTask(rootDir, relativePath);\n}\n\nexport async function updateTask(rootDir: string, currentPath: string, input: UpdateTaskInput): Promise<TaskRecord> {\n const normalizedCurrentPath = ensureMarkdownExtension(normalizeRelativePath(currentPath));\n const absoluteCurrentPath = path.join(rootDir, normalizedCurrentPath);\n\n let existing: TaskRecord;\n try {\n existing = await parseTask(rootDir, normalizedCurrentPath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n throw new ConflictError(\"The task no longer exists.\");\n }\n throw error;\n }\n\n if (input.baseUpdatedAt && existing.frontmatter.updatedAt !== input.baseUpdatedAt) {\n throw new ConflictError(\"The task changed on disk. Reload before saving.\");\n }\n\n const nextPath = input.path?.trim()\n ? await ensureDirectoryForFile(rootDir, input.path)\n : normalizedCurrentPath;\n const absoluteNextPath = path.join(rootDir, nextPath);\n\n if (nextPath !== normalizedCurrentPath) {\n try {\n await fs.access(absoluteNextPath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n // The target path is available.\n } else if (maybeError.code) {\n throw error;\n } else {\n throw new ValidationError(\"A task already exists at the target path.\");\n }\n }\n }\n\n const record: TaskRecord = {\n path: nextPath,\n raw: existing.raw,\n normalized: false,\n content: input.content,\n extraFrontmatter: input.extraFrontmatter ?? existing.extraFrontmatter,\n frontmatter: {\n title: input.title.trim(),\n priority: input.priority,\n status: input.status,\n createdAt: existing.frontmatter.createdAt,\n updatedAt: asUtcISOString(new Date())\n }\n };\n\n await fs.writeFile(absoluteCurrentPath, serializeTask(record), \"utf8\");\n if (nextPath !== normalizedCurrentPath) {\n await fs.mkdir(path.dirname(absoluteNextPath), { recursive: true });\n await fs.rename(absoluteCurrentPath, absoluteNextPath);\n }\n\n const current = await listTasks(rootDir);\n const updatedOrder = current.tasks.map((task) => task.path);\n await saveOrder(rootDir, updatedOrder);\n return parseTask(rootDir, nextPath);\n}\n\nexport async function deleteTask(rootDir: string, relativePath: string): Promise<void> {\n const normalizedPath = ensureMarkdownExtension(normalizeRelativePath(relativePath));\n const absolutePath = path.join(rootDir, normalizedPath);\n\n try {\n await fs.unlink(absolutePath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n throw new ConflictError(\"The task no longer exists.\");\n }\n throw error;\n }\n\n const current = await listTasks(rootDir);\n await saveOrder(\n rootDir,\n current.tasks.map((task) => task.path)\n );\n}\n\nexport async function patchTaskFields(rootDir: string, currentPath: string, input: PatchTaskFieldsInput): Promise<TaskRecord> {\n const normalizedCurrentPath = ensureMarkdownExtension(normalizeRelativePath(currentPath));\n const absoluteCurrentPath = path.join(rootDir, normalizedCurrentPath);\n\n let existing: TaskRecord;\n try {\n existing = await parseTask(rootDir, normalizedCurrentPath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n throw new ConflictError(\"The task no longer exists.\");\n }\n throw error;\n }\n\n const priority = input.priority && REQUIRED_PRIORITY.includes(input.priority) ? input.priority : existing.frontmatter.priority;\n const status = input.status && REQUIRED_STATUS.includes(input.status) ? input.status : existing.frontmatter.status;\n\n if (priority === existing.frontmatter.priority && status === existing.frontmatter.status) {\n return existing;\n }\n\n const record: TaskRecord = {\n path: normalizedCurrentPath,\n raw: existing.raw,\n normalized: false,\n content: existing.content,\n extraFrontmatter: existing.extraFrontmatter,\n frontmatter: {\n ...existing.frontmatter,\n priority,\n status,\n updatedAt: asUtcISOString(new Date())\n }\n };\n\n await fs.writeFile(absoluteCurrentPath, serializeTask(record), \"utf8\");\n return parseTask(rootDir, normalizedCurrentPath);\n}\n\nexport function parseOrderPayload(input: unknown): string[] {\n if (!Array.isArray(input)) {\n throw new ValidationError(\"Order payload must be an array.\");\n }\n\n return input.map((item) => ensureMarkdownExtension(normalizeRelativePath(String(item))));\n}\n\nexport async function readOrder(rootDir: string): Promise<ConfigFile> {\n const config = await readConfig(rootDir);\n const { order } = await reconcileOrder(\n rootDir,\n (await listTasks(rootDir)).tasks.map((task) => task.path)\n );\n return { version: 1, taskDirs: config.taskDirs, ignorePaths: config.ignorePaths, order, commands: config.commands };\n}\n\nexport const taskStoreUtils = {\n slugify,\n normalizeRelativePath,\n ensureMarkdownExtension,\n splitFrontmatter,\n buildDefaults\n};\n","export const CONFIG_FILE_NAME = \".md-task-viewer.json\";\n\nexport type TaskPriority = \"MUST\" | \"WANT\";\nexport type TaskStatus = \"TODO\" | \"WIP\" | \"DONE\";\n\nexport interface TaskFrontmatter {\n title: string;\n priority: TaskPriority;\n status: TaskStatus;\n createdAt: string;\n updatedAt: string;\n [key: string]: unknown;\n}\n\nexport interface TaskRecord {\n path: string;\n content: string;\n frontmatter: TaskFrontmatter;\n extraFrontmatter: Record<string, unknown>;\n raw: string;\n normalized: boolean;\n}\n\nexport interface TaskParseError {\n path: string;\n message: string;\n}\n\nexport interface TaskListResponse {\n tasks: TaskRecord[];\n errors: TaskParseError[];\n}\n\nexport interface CreateTaskInput {\n title: string;\n priority?: TaskPriority;\n status?: TaskStatus;\n content?: string;\n directory?: string;\n path?: string;\n extraFrontmatter?: Record<string, unknown>;\n}\n\nexport interface UpdateTaskInput {\n path?: string;\n title: string;\n priority: TaskPriority;\n status: TaskStatus;\n content: string;\n extraFrontmatter?: Record<string, unknown>;\n baseUpdatedAt?: string;\n}\n\nexport interface PatchTaskFieldsInput {\n priority?: TaskPriority;\n status?: TaskStatus;\n}\n\nexport interface CommandStep {\n command: string;\n passBody?: \"arg\" | \"stdin\" | false;\n}\n\nexport interface CommandExecutionResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n duration: number;\n}\n\nexport interface ConfigFile {\n version: number;\n taskDirs: string[];\n ignorePaths: string[];\n order: string[];\n commands?: CommandStep[];\n}\n","export function slugify(value: string): string {\n const slug = value\n // Unicode結合文字列を正規合成形に統一(例: か+濁点 → が)\n .normalize(\"NFC\")\n // 半角・全角スペース(U+3000)など空白文字をハイフンに変換。近年では \\s は U+3000 にもマッチするが、明示的に記載\n .replace(/[\\s\\u3000]+/g, \"-\")\n // Unicode文字(L)・数字(N)・ハイフン以外を除去(記号や句読点など)\n .replace(/[^\\p{L}\\p{N}-]+/gu, \"\")\n // 先頭・末尾の余分なハイフンを除去\n .replace(/^-+|-+$/g, \"\");\n return slug || \"untitled-task\";\n}\n","import { spawn } from \"node:child_process\";\nimport path from \"node:path\";\nimport type { CommandStep, CommandExecutionResult, TaskRecord } from \"./types.js\";\n\nconst TIMEOUT_MS = 30_000;\n\nconst VARIABLE_PATTERN = /\\$\\{?(TASK_TITLE|TASK_FILEPATH|TASK_BODY)\\}?/g;\n\nexport function substituteVariables(command: string, vars: Record<string, string>): string {\n return command.replace(VARIABLE_PATTERN, (_match, name: string) => vars[name] ?? \"\");\n}\n\nexport async function executeCommandPipeline(\n rootDir: string,\n steps: CommandStep[],\n task: TaskRecord\n): Promise<CommandExecutionResult> {\n if (steps.length === 0) {\n return { stdout: \"\", stderr: \"\", exitCode: 0, duration: 0 };\n }\n\n const absoluteFilePath = path.resolve(rootDir, task.path);\n const vars: Record<string, string> = {\n TASK_TITLE: task.frontmatter.title,\n TASK_FILEPATH: absoluteFilePath,\n TASK_BODY: task.content\n };\n\n const startTime = Date.now();\n\n return new Promise<CommandExecutionResult>((resolve) => {\n const resolvedCommands = steps.map((step, index) => {\n let cmd = substituteVariables(step.command, vars);\n if (index === 0 && step.passBody === \"arg\") {\n const escaped = task.content.replace(/'/g, \"'\\\\''\");\n cmd = `${cmd} '${escaped}'`;\n }\n return cmd;\n });\n\n const processes: ReturnType<typeof spawn>[] = [];\n for (let index = 0; index < resolvedCommands.length; index++) {\n const proc = spawn(resolvedCommands[index], {\n shell: true,\n cwd: rootDir,\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n\n // pipe stdout of previous process to stdin of current\n if (index > 0) {\n const prev = processes[index - 1];\n if (prev?.stdout) {\n prev.stdout.pipe(proc.stdin!);\n }\n }\n\n processes.push(proc);\n }\n\n // Handle first command's passBody option\n const firstStep = steps[0];\n const firstProc = processes[0];\n if (firstStep.passBody === \"stdin\" && firstProc.stdin) {\n firstProc.stdin.write(task.content);\n }\n // Always close first process stdin (body written above if passBody is stdin)\n firstProc.stdin?.end();\n\n const lastProc = processes[processes.length - 1];\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n lastProc.stdout?.on(\"data\", (chunk: Buffer) => stdoutChunks.push(chunk));\n lastProc.stderr?.on(\"data\", (chunk: Buffer) => stderrChunks.push(chunk));\n\n // Collect stderr from all intermediate processes too\n for (let i = 0; i < processes.length - 1; i++) {\n processes[i].stderr?.on(\"data\", (chunk: Buffer) => stderrChunks.push(chunk));\n }\n\n const timeout = setTimeout(() => {\n for (const proc of processes) {\n proc.kill(\"SIGTERM\");\n }\n }, TIMEOUT_MS);\n\n lastProc.on(\"close\", (code) => {\n clearTimeout(timeout);\n resolve({\n stdout: Buffer.concat(stdoutChunks).toString(\"utf8\"),\n stderr: Buffer.concat(stderrChunks).toString(\"utf8\"),\n exitCode: code ?? 1,\n duration: Date.now() - startTime\n });\n });\n\n lastProc.on(\"error\", (err) => {\n clearTimeout(timeout);\n resolve({\n stdout: \"\",\n stderr: err.message,\n exitCode: 1,\n duration: Date.now() - startTime\n });\n });\n\n // Handle errors on intermediate processes\n for (let i = 0; i < processes.length - 1; i++) {\n processes[i].on(\"error\", (err) => {\n stderrChunks.push(Buffer.from(err.message));\n });\n }\n });\n}\n"],"mappings":"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","names":["path","path","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/taskStore.ts","../src/types.ts","../src/slugify.ts","../src/commandExecutor.ts"],"sourcesContent":["import Fastify, { type FastifyInstance } from \"fastify\";\nimport fastifyStatic from \"@fastify/static\";\nimport chokidar from \"chokidar\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n ConflictError,\n ValidationError,\n createTask,\n deleteTask,\n listTasks,\n parseOrderPayload,\n parseTask,\n patchTaskFields,\n readConfig,\n saveConfig,\n saveOrder,\n updateTask\n} from \"./taskStore.js\";\nimport type { CommandStep } from \"./types.js\";\nimport { executeCommandPipeline } from \"./commandExecutor.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface CreateServerOptions {\n rootDir: string;\n clientDir?: string | null;\n}\n\nfunction resolveClientDir(explicitClientDir?: string | null): string | null {\n if (explicitClientDir === null) {\n return null;\n }\n if (explicitClientDir) {\n return explicitClientDir;\n }\n return path.resolve(__dirname, \"client\");\n}\n\nfunction sendJsonError(reply: { code: (statusCode: number) => { send: (payload: unknown) => void } }, error: unknown): void {\n if (error instanceof ValidationError) {\n reply.code(400).send({ error: error.message });\n return;\n }\n if (error instanceof ConflictError) {\n reply.code(409).send({ error: error.message });\n return;\n }\n reply.code(500).send({ error: error instanceof Error ? error.message : \"Internal server error\" });\n}\n\nexport async function createServer(options: CreateServerOptions): Promise<FastifyInstance> {\n const app = Fastify({ logger: false });\n const listeners = new Set<{ send: (payload: string) => void; close: () => void }>();\n const clientDir = resolveClientDir(options.clientDir);\n\n app.addHook(\"onClose\", async () => {\n for (const listener of listeners) {\n listener.close();\n }\n });\n\n app.get(\"/api/tasks\", async () => listTasks(options.rootDir));\n\n app.post(\"/api/tasks\", async (request, reply) => {\n try {\n const task = await createTask(options.rootDir, (request.body ?? {}) as never);\n return reply.code(201).send(task);\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.patch(\"/api/tasks/*\", async (request, reply) => {\n const currentPath = decodeURIComponent((request.params as { \"*\": string })[\"*\"] ?? \"\");\n try {\n const task = await updateTask(options.rootDir, currentPath, (request.body ?? {}) as never);\n return reply.send(task);\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.delete(\"/api/tasks/*\", async (request, reply) => {\n const currentPath = decodeURIComponent((request.params as { \"*\": string })[\"*\"] ?? \"\");\n try {\n await deleteTask(options.rootDir, currentPath);\n return reply.code(204).send();\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.patch(\"/api/task-fields/*\", async (request, reply) => {\n const currentPath = decodeURIComponent((request.params as { \"*\": string })[\"*\"] ?? \"\");\n try {\n const task = await patchTaskFields(options.rootDir, currentPath, (request.body ?? {}) as never);\n return reply.send(task);\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.put(\"/api/order\", async (request, reply) => {\n try {\n const order = parseOrderPayload((request.body as { order?: unknown } | null)?.order ?? []);\n await saveOrder(options.rootDir, order);\n return reply.code(204).send();\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.get(\"/api/config\", async () => {\n try {\n return await readConfig(options.rootDir);\n } catch (error) {\n return { version: 1, taskDirs: [\".\"], order: [] };\n }\n });\n\n app.put(\"/api/config\", async (request, reply) => {\n try {\n const body = request.body as { taskDirs?: unknown; ignorePaths?: unknown; commands?: unknown } | null;\n const taskDirs = body?.taskDirs;\n if (!Array.isArray(taskDirs) || taskDirs.some((item) => typeof item !== \"string\")) {\n throw new ValidationError(\"taskDirs must be an array of strings.\");\n }\n let ignorePaths: string[] | undefined;\n if (body?.ignorePaths !== undefined) {\n if (!Array.isArray(body.ignorePaths) || body.ignorePaths.some((item) => typeof item !== \"string\")) {\n throw new ValidationError(\"ignorePaths must be an array of strings.\");\n }\n ignorePaths = body.ignorePaths as string[];\n }\n let commands: CommandStep[] | undefined;\n if (body?.commands !== undefined) {\n if (!Array.isArray(body.commands)) {\n throw new ValidationError(\"commands must be an array.\");\n }\n commands = body.commands as CommandStep[];\n }\n const config = await saveConfig(options.rootDir, taskDirs as string[], ignorePaths, commands);\n return reply.send(config);\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.post(\"/api/execute\", async (request, reply) => {\n try {\n const body = request.body as { taskPath?: string; commands?: CommandStep[] } | null;\n const taskPath = body?.taskPath;\n if (!taskPath || typeof taskPath !== \"string\") {\n throw new ValidationError(\"taskPath is required.\");\n }\n\n let task;\n try {\n task = await parseTask(options.rootDir, taskPath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n return reply.code(404).send({ error: \"Task not found.\" });\n }\n throw error;\n }\n\n // Resolve commands: request body > task extraFrontmatter > global config\n let commands = body?.commands;\n if (!commands || commands.length === 0) {\n const taskCommands = task.extraFrontmatter.commands;\n if (Array.isArray(taskCommands) && taskCommands.length > 0) {\n commands = taskCommands as CommandStep[];\n }\n }\n if (!commands || commands.length === 0) {\n const config = await readConfig(options.rootDir);\n commands = config.commands;\n }\n if (!commands || commands.length === 0) {\n throw new ValidationError(\"No commands configured.\");\n }\n\n const result = await executeCommandPipeline(options.rootDir, commands, task);\n return reply.send(result);\n } catch (error) {\n sendJsonError(reply, error);\n }\n });\n\n app.get(\"/api/events\", async (_request, reply) => {\n reply.raw.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\"\n });\n reply.raw.write(\"\\n\");\n\n const listener = {\n send(payload: string) {\n reply.raw.write(`data: ${payload}\\n\\n`);\n },\n close() {\n reply.raw.end();\n }\n };\n\n listeners.add(listener);\n reply.raw.on(\"close\", () => {\n listeners.delete(listener);\n });\n\n return reply.hijack();\n });\n\n const watcher = chokidar.watch(options.rootDir, {\n ignoreInitial: true,\n ignored: (watchPath) => watchPath.includes(`${path.sep}.git`) || watchPath.includes(`${path.sep}node_modules`)\n });\n\n watcher.on(\"all\", (eventName, changedPath) => {\n const isMarkdown = changedPath.endsWith(\".md\") || changedPath.endsWith(\".markdown\");\n const isConfigFile = path.basename(changedPath) === \".md-task-viewer.json\";\n if (!isMarkdown && !isConfigFile) {\n return;\n }\n\n const payload = JSON.stringify({\n type: \"tasks-changed\",\n eventName,\n path: path.relative(options.rootDir, changedPath)\n });\n\n for (const listener of listeners) {\n listener.send(payload);\n }\n });\n\n app.addHook(\"onClose\", async () => {\n await watcher.close();\n });\n\n if (clientDir) {\n await app.register(fastifyStatic, {\n root: clientDir,\n prefix: \"/\"\n });\n\n app.setNotFoundHandler(async (request, reply) => {\n if (request.raw.url?.startsWith(\"/api/\")) {\n return reply.code(404).send({ error: \"Not found\" });\n }\n return reply.sendFile(\"index.html\");\n });\n }\n\n return app;\n}\n","import matter from \"gray-matter\";\nimport picomatch from \"picomatch\";\nimport path from \"node:path\";\nimport { promises as fs } from \"node:fs\";\nimport {\n CONFIG_FILE_NAME,\n type CommandStep,\n type ConfigFile,\n type CreateTaskInput,\n type PatchTaskFieldsInput,\n type TaskFrontmatter,\n type TaskListResponse,\n type TaskParseError,\n type TaskPriority,\n type TaskRecord,\n type TaskStatus,\n type UpdateTaskInput\n} from \"./types.js\";\nimport { slugify } from \"./slugify.js\";\n\nconst MARKDOWN_EXTENSIONS = new Set([\".md\", \".markdown\"]);\nconst REQUIRED_PRIORITY: TaskPriority[] = [\"MUST\", \"WANT\"];\nconst REQUIRED_STATUS: TaskStatus[] = [\"TODO\", \"WIP\", \"DONE\"];\n\nexport class ConflictError extends Error {}\nexport class ValidationError extends Error {}\n\nfunction toPosixPath(filePath: string): string {\n return filePath.split(path.sep).join(\"/\");\n}\n\nfunction normalizeRelativePath(candidate: string): string {\n const normalized = toPosixPath(path.posix.normalize(candidate.trim()));\n if (!normalized || normalized === \".\" || normalized.startsWith(\"../\") || normalized.includes(\"/../\")) {\n throw new ValidationError(\"Path must stay within the workspace root.\");\n }\n\n return normalized.replace(/^\\.\\/+/, \"\");\n}\n\nfunction ensureMarkdownExtension(filePath: string): string {\n return path.posix.extname(filePath) ? filePath : `${filePath}.md`;\n}\n\nfunction asUtcISOString(date: Date): string {\n return date.toISOString();\n}\n\nfunction buildDefaults(filePath: string, stats: { birthtime: Date; mtime: Date }): TaskFrontmatter {\n const basename = path.basename(filePath, path.extname(filePath));\n const title = basename.replace(/[-_]+/g, \" \").replace(/\\b\\w/g, (char) => char.toUpperCase());\n\n return {\n title,\n priority: \"WANT\",\n status: \"TODO\",\n createdAt: asUtcISOString(stats.birthtime),\n updatedAt: asUtcISOString(stats.mtime)\n };\n}\n\nfunction splitFrontmatter(data: Record<string, unknown>, statsDefaults: TaskFrontmatter): {\n frontmatter: TaskFrontmatter;\n extraFrontmatter: Record<string, unknown>;\n normalized: boolean;\n} {\n const extraFrontmatter: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(data)) {\n if (![\"title\", \"priority\", \"status\", \"createdAt\", \"updatedAt\"].includes(key)) {\n extraFrontmatter[key] = value;\n }\n }\n\n const title = typeof data.title === \"string\" && data.title.trim() ? data.title : statsDefaults.title;\n const priority = REQUIRED_PRIORITY.includes(data.priority as TaskPriority)\n ? (data.priority as TaskPriority)\n : statsDefaults.priority;\n const status = REQUIRED_STATUS.includes(data.status as TaskStatus)\n ? (data.status as TaskStatus)\n : statsDefaults.status;\n const createdAt =\n typeof data.createdAt === \"string\" && !Number.isNaN(Date.parse(data.createdAt))\n ? new Date(data.createdAt).toISOString()\n : statsDefaults.createdAt;\n const updatedAt =\n typeof data.updatedAt === \"string\" && !Number.isNaN(Date.parse(data.updatedAt))\n ? new Date(data.updatedAt).toISOString()\n : statsDefaults.updatedAt;\n\n const normalized =\n title !== data.title ||\n priority !== data.priority ||\n status !== data.status ||\n createdAt !== data.createdAt ||\n updatedAt !== data.updatedAt;\n\n return {\n frontmatter: { title, priority, status, createdAt, updatedAt },\n extraFrontmatter,\n normalized\n };\n}\n\nexport function serializeTask(record: TaskRecord): string {\n const data = {\n ...record.extraFrontmatter,\n title: record.frontmatter.title,\n priority: record.frontmatter.priority,\n status: record.frontmatter.status,\n createdAt: record.frontmatter.createdAt,\n updatedAt: record.frontmatter.updatedAt\n };\n\n return matter.stringify(record.content, data);\n}\n\nasync function readDirectoryRecursive(rootDir: string, currentDir: string, results: string[]): Promise<void> {\n const entries = await fs.readdir(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.name === \".git\" || entry.name === \"node_modules\") {\n continue;\n }\n\n const absolutePath = path.join(currentDir, entry.name);\n if (entry.isDirectory()) {\n await readDirectoryRecursive(rootDir, absolutePath, results);\n continue;\n }\n\n if (entry.name === CONFIG_FILE_NAME) {\n continue;\n }\n\n if (!MARKDOWN_EXTENSIONS.has(path.extname(entry.name).toLowerCase())) {\n continue;\n }\n\n results.push(toPosixPath(path.relative(rootDir, absolutePath)));\n }\n}\n\nasync function listMarkdownFiles(rootDir: string, taskDirs: string[], ignorePaths: string[]): Promise<string[]> {\n const results: string[] = [];\n const seen = new Set<string>();\n\n const isIgnored = ignorePaths.length > 0 ? picomatch(ignorePaths) : null;\n\n for (const taskDir of taskDirs) {\n const scanDir = path.resolve(rootDir, taskDir);\n try {\n await fs.access(scanDir);\n } catch {\n continue;\n }\n const dirResults: string[] = [];\n await readDirectoryRecursive(rootDir, scanDir, dirResults);\n for (const filePath of dirResults) {\n if (!seen.has(filePath)) {\n seen.add(filePath);\n if (isIgnored && isIgnored(filePath)) {\n continue;\n }\n results.push(filePath);\n }\n }\n }\n\n return results.sort();\n}\n\nexport async function parseTask(rootDir: string, relativePath: string): Promise<TaskRecord> {\n const absolutePath = path.join(rootDir, relativePath);\n const raw = await fs.readFile(absolutePath, \"utf8\");\n const stats = await fs.stat(absolutePath);\n const parsed = matter(raw);\n const defaults = buildDefaults(relativePath, stats);\n const { frontmatter, extraFrontmatter, normalized } = splitFrontmatter(parsed.data, defaults);\n\n return {\n path: toPosixPath(relativePath),\n content: parsed.content,\n frontmatter,\n extraFrontmatter,\n raw,\n normalized\n };\n}\n\nexport async function readConfig(rootDir: string): Promise<ConfigFile> {\n const configFilePath = path.join(rootDir, CONFIG_FILE_NAME);\n\n try {\n const raw = await fs.readFile(configFilePath, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<ConfigFile>;\n const taskDirs = Array.isArray(parsed.taskDirs)\n ? parsed.taskDirs.filter((item): item is string => typeof item === \"string\")\n : [\".\"];\n const ignorePaths = Array.isArray(parsed.ignorePaths)\n ? parsed.ignorePaths.filter((item): item is string => typeof item === \"string\")\n : [];\n const order = Array.isArray(parsed.order)\n ? parsed.order.filter((item): item is string => typeof item === \"string\")\n : [];\n const commands = Array.isArray(parsed.commands)\n ? (parsed.commands as CommandStep[])\n : undefined;\n return { version: parsed.version ?? 1, taskDirs, ignorePaths, order, commands };\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code !== \"ENOENT\") {\n throw error;\n }\n return { version: 1, taskDirs: [\".\"], ignorePaths: [], order: [] };\n }\n}\n\nasync function reconcileOrder(rootDir: string, taskPaths: string[]): Promise<{ order: string[]; changed: boolean }> {\n const config = await readConfig(rootDir);\n const order = config.order;\n\n const known = new Set(taskPaths);\n const orderSet = new Set(order);\n\n const newItems = taskPaths.filter((p) => !orderSet.has(p));\n const removedCount = order.reduce((count, item) => (known.has(item) ? count : count + 1), 0);\n const canReplace = newItems.length > 0 && newItems.length === removedCount;\n\n // Build next order:\n // - Always keep existing items in their original relative positions.\n // - Only replace removed slots with new items when the number of removed\n // items exactly matches the number of new items (rename-like scenario).\n // - Otherwise, skip removed items and append all new items at the end to\n // avoid unexpected reordering.\n const nextOrder: string[] = [];\n let newItemCursor = 0;\n for (let i = 0; i < order.length; i++) {\n if (known.has(order[i])) {\n nextOrder.push(order[i]);\n } else if (canReplace && newItemCursor < newItems.length) {\n nextOrder.push(newItems[newItemCursor++]);\n }\n // else: removed item with no replacement — skip\n }\n // Append any remaining new items (all of them when we are not in a replace scenario)\n while (newItemCursor < newItems.length) {\n nextOrder.push(newItems[newItemCursor++]);\n }\n\n const changed = nextOrder.length !== order.length || nextOrder.some((item, index) => item !== order[index]);\n return { order: nextOrder, changed };\n}\n\nexport async function saveOrder(rootDir: string, order: string[]): Promise<void> {\n const normalized = Array.from(\n new Set(\n order.map((item) => ensureMarkdownExtension(normalizeRelativePath(item)))\n )\n );\n const existing = await readConfig(rootDir);\n const payload: ConfigFile = { version: 1, taskDirs: existing.taskDirs, ignorePaths: existing.ignorePaths, order: normalized, commands: existing.commands };\n await fs.writeFile(path.join(rootDir, CONFIG_FILE_NAME), `${JSON.stringify(payload, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function saveConfig(rootDir: string, taskDirs: string[], ignorePaths?: string[], commands?: CommandStep[]): Promise<ConfigFile> {\n const validated = taskDirs.map((dir) => {\n const normalized = dir.trim().replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\") || \".\";\n if (normalized.startsWith(\"../\") || normalized.includes(\"/../\")) {\n throw new ValidationError(\"taskDirs must stay within the workspace root.\");\n }\n return normalized;\n });\n if (validated.length === 0) {\n throw new ValidationError(\"taskDirs must contain at least one directory.\");\n }\n const existing = await readConfig(rootDir);\n const validatedIgnorePaths = ignorePaths ?? existing.ignorePaths;\n const validatedCommands = commands !== undefined ? commands : existing.commands;\n const payload: ConfigFile = { version: 1, taskDirs: validated, ignorePaths: validatedIgnorePaths, order: existing.order, commands: validatedCommands };\n await fs.writeFile(path.join(rootDir, CONFIG_FILE_NAME), `${JSON.stringify(payload, null, 2)}\\n`, \"utf8\");\n return payload;\n}\n\nexport async function listTasks(rootDir: string): Promise<TaskListResponse> {\n const config = await readConfig(rootDir);\n const files = await listMarkdownFiles(rootDir, config.taskDirs, config.ignorePaths);\n const errors: TaskParseError[] = [];\n const tasks = await Promise.all(\n files.map(async (relativePath) => {\n try {\n return await parseTask(rootDir, relativePath);\n } catch (error) {\n errors.push({\n path: relativePath,\n message: error instanceof Error ? error.message : \"Unknown parse error\"\n });\n return null;\n }\n })\n );\n\n const taskRecords = tasks.filter((task): task is TaskRecord => task !== null);\n const { order, changed } = await reconcileOrder(\n rootDir,\n taskRecords.map((task) => task.path)\n );\n\n if (changed) {\n await saveOrder(rootDir, order);\n }\n\n const orderIndex = new Map(order.map((item, index) => [item, index]));\n taskRecords.sort((left, right) => {\n const leftIndex = orderIndex.get(left.path) ?? Number.MAX_SAFE_INTEGER;\n const rightIndex = orderIndex.get(right.path) ?? Number.MAX_SAFE_INTEGER;\n return leftIndex - rightIndex || left.path.localeCompare(right.path);\n });\n\n return { tasks: taskRecords, errors };\n}\n\nasync function ensureDirectoryForFile(rootDir: string, relativeFilePath: string): Promise<string> {\n const normalized = ensureMarkdownExtension(normalizeRelativePath(relativeFilePath));\n const absolutePath = path.join(rootDir, normalized);\n const directory = path.dirname(absolutePath);\n await fs.mkdir(directory, { recursive: true });\n return normalized;\n}\n\nasync function nextAvailablePath(rootDir: string, directory: string, title: string): Promise<string> {\n const safeDirectory = directory ? normalizeRelativePath(directory) : \"\";\n const slug = slugify(title);\n const base = safeDirectory ? `${safeDirectory}/${slug}` : slug;\n\n let attempt = 0;\n while (true) {\n const candidate = ensureMarkdownExtension(attempt === 0 ? base : `${base}-${attempt + 1}`);\n try {\n await fs.access(path.join(rootDir, candidate));\n attempt += 1;\n } catch {\n return candidate;\n }\n }\n}\n\nexport async function createTask(rootDir: string, input: CreateTaskInput): Promise<TaskRecord> {\n if (!input.title.trim()) {\n throw new ValidationError(\"Title is required.\");\n }\n\n const now = asUtcISOString(new Date());\n const relativePath = input.path?.trim()\n ? await ensureDirectoryForFile(rootDir, input.path)\n : await nextAvailablePath(rootDir, input.directory ?? \"\", input.title);\n const absolutePath = path.join(rootDir, relativePath);\n\n try {\n await fs.access(absolutePath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n // The target path is available.\n } else if (maybeError.code) {\n throw error;\n } else {\n throw new ValidationError(\"A task already exists at that path.\");\n }\n }\n\n const record: TaskRecord = {\n path: relativePath,\n content: input.content ?? \"\",\n raw: \"\",\n normalized: false,\n extraFrontmatter: input.extraFrontmatter ?? {},\n frontmatter: {\n title: input.title.trim(),\n priority: input.priority ?? \"MUST\",\n status: input.status ?? \"TODO\",\n createdAt: now,\n updatedAt: now\n }\n };\n\n await fs.mkdir(path.dirname(absolutePath), { recursive: true });\n await fs.writeFile(absolutePath, serializeTask(record), \"utf8\");\n\n const current = await listTasks(rootDir);\n await saveOrder(rootDir, current.tasks.map((task) => task.path).concat(relativePath));\n return parseTask(rootDir, relativePath);\n}\n\nexport async function updateTask(rootDir: string, currentPath: string, input: UpdateTaskInput): Promise<TaskRecord> {\n const normalizedCurrentPath = ensureMarkdownExtension(normalizeRelativePath(currentPath));\n const absoluteCurrentPath = path.join(rootDir, normalizedCurrentPath);\n\n let existing: TaskRecord;\n try {\n existing = await parseTask(rootDir, normalizedCurrentPath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n throw new ConflictError(\"The task no longer exists.\");\n }\n throw error;\n }\n\n if (input.baseUpdatedAt && existing.frontmatter.updatedAt !== input.baseUpdatedAt) {\n throw new ConflictError(\"The task changed on disk. Reload before saving.\");\n }\n\n const nextPath = input.path?.trim()\n ? await ensureDirectoryForFile(rootDir, input.path)\n : normalizedCurrentPath;\n const absoluteNextPath = path.join(rootDir, nextPath);\n\n if (nextPath !== normalizedCurrentPath) {\n try {\n await fs.access(absoluteNextPath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n // The target path is available.\n } else if (maybeError.code) {\n throw error;\n } else {\n throw new ValidationError(\"A task already exists at the target path.\");\n }\n }\n }\n\n const record: TaskRecord = {\n path: nextPath,\n raw: existing.raw,\n normalized: false,\n content: input.content,\n extraFrontmatter: input.extraFrontmatter ?? existing.extraFrontmatter,\n frontmatter: {\n title: input.title.trim(),\n priority: input.priority,\n status: input.status,\n createdAt: existing.frontmatter.createdAt,\n updatedAt: asUtcISOString(new Date())\n }\n };\n\n await fs.writeFile(absoluteCurrentPath, serializeTask(record), \"utf8\");\n if (nextPath !== normalizedCurrentPath) {\n await fs.mkdir(path.dirname(absoluteNextPath), { recursive: true });\n await fs.rename(absoluteCurrentPath, absoluteNextPath);\n }\n\n if (nextPath !== normalizedCurrentPath) {\n const config = await readConfig(rootDir);\n const filteredOrder = config.order.filter((item) => item !== nextPath);\n const index = filteredOrder.indexOf(normalizedCurrentPath);\n\n let updatedOrder: string[];\n if (index === -1) {\n // If the old path is not present, just append the new path.\n updatedOrder = [...filteredOrder, nextPath];\n } else {\n // Replace the old path with the new path at the same position.\n updatedOrder = [...filteredOrder];\n updatedOrder[index] = nextPath;\n }\n await saveOrder(rootDir, updatedOrder);\n }\n return parseTask(rootDir, nextPath);\n}\n\nexport async function deleteTask(rootDir: string, relativePath: string): Promise<void> {\n const normalizedPath = ensureMarkdownExtension(normalizeRelativePath(relativePath));\n const absolutePath = path.join(rootDir, normalizedPath);\n\n try {\n await fs.unlink(absolutePath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n throw new ConflictError(\"The task no longer exists.\");\n }\n throw error;\n }\n\n const current = await listTasks(rootDir);\n await saveOrder(\n rootDir,\n current.tasks.map((task) => task.path)\n );\n}\n\nexport async function patchTaskFields(rootDir: string, currentPath: string, input: PatchTaskFieldsInput): Promise<TaskRecord> {\n const normalizedCurrentPath = ensureMarkdownExtension(normalizeRelativePath(currentPath));\n const absoluteCurrentPath = path.join(rootDir, normalizedCurrentPath);\n\n let existing: TaskRecord;\n try {\n existing = await parseTask(rootDir, normalizedCurrentPath);\n } catch (error) {\n const maybeError = error as NodeJS.ErrnoException;\n if (maybeError.code === \"ENOENT\") {\n throw new ConflictError(\"The task no longer exists.\");\n }\n throw error;\n }\n\n const priority = input.priority && REQUIRED_PRIORITY.includes(input.priority) ? input.priority : existing.frontmatter.priority;\n const status = input.status && REQUIRED_STATUS.includes(input.status) ? input.status : existing.frontmatter.status;\n\n if (priority === existing.frontmatter.priority && status === existing.frontmatter.status) {\n return existing;\n }\n\n const record: TaskRecord = {\n path: normalizedCurrentPath,\n raw: existing.raw,\n normalized: false,\n content: existing.content,\n extraFrontmatter: existing.extraFrontmatter,\n frontmatter: {\n ...existing.frontmatter,\n priority,\n status,\n updatedAt: asUtcISOString(new Date())\n }\n };\n\n await fs.writeFile(absoluteCurrentPath, serializeTask(record), \"utf8\");\n return parseTask(rootDir, normalizedCurrentPath);\n}\n\nexport function parseOrderPayload(input: unknown): string[] {\n if (!Array.isArray(input)) {\n throw new ValidationError(\"Order payload must be an array.\");\n }\n\n return input.map((item) => ensureMarkdownExtension(normalizeRelativePath(String(item))));\n}\n\nexport async function readOrder(rootDir: string): Promise<ConfigFile> {\n const config = await readConfig(rootDir);\n const { order } = await reconcileOrder(\n rootDir,\n (await listTasks(rootDir)).tasks.map((task) => task.path)\n );\n return { version: 1, taskDirs: config.taskDirs, ignorePaths: config.ignorePaths, order, commands: config.commands };\n}\n\nexport const taskStoreUtils = {\n slugify,\n normalizeRelativePath,\n ensureMarkdownExtension,\n splitFrontmatter,\n buildDefaults\n};\n","export const CONFIG_FILE_NAME = \".md-task-viewer.json\";\n\nexport type TaskPriority = \"MUST\" | \"WANT\";\nexport type TaskStatus = \"TODO\" | \"WIP\" | \"DONE\";\n\nexport interface TaskFrontmatter {\n title: string;\n priority: TaskPriority;\n status: TaskStatus;\n createdAt: string;\n updatedAt: string;\n [key: string]: unknown;\n}\n\nexport interface TaskRecord {\n path: string;\n content: string;\n frontmatter: TaskFrontmatter;\n extraFrontmatter: Record<string, unknown>;\n raw: string;\n normalized: boolean;\n}\n\nexport interface TaskParseError {\n path: string;\n message: string;\n}\n\nexport interface TaskListResponse {\n tasks: TaskRecord[];\n errors: TaskParseError[];\n}\n\nexport interface CreateTaskInput {\n title: string;\n priority?: TaskPriority;\n status?: TaskStatus;\n content?: string;\n directory?: string;\n path?: string;\n extraFrontmatter?: Record<string, unknown>;\n}\n\nexport interface UpdateTaskInput {\n path?: string;\n title: string;\n priority: TaskPriority;\n status: TaskStatus;\n content: string;\n extraFrontmatter?: Record<string, unknown>;\n baseUpdatedAt?: string;\n}\n\nexport interface PatchTaskFieldsInput {\n priority?: TaskPriority;\n status?: TaskStatus;\n}\n\nexport interface CommandStep {\n command: string;\n passBody?: \"arg\" | \"stdin\" | false;\n}\n\nexport interface CommandExecutionResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n duration: number;\n}\n\nexport interface ConfigFile {\n version: number;\n taskDirs: string[];\n ignorePaths: string[];\n order: string[];\n commands?: CommandStep[];\n}\n","export function slugify(value: string): string {\n const slug = value\n // Unicode結合文字列を正規合成形に統一(例: か+濁点 → が)\n .normalize(\"NFC\")\n // 半角・全角スペース(U+3000)など空白文字をハイフンに変換。近年では \\s は U+3000 にもマッチするが、明示的に記載\n .replace(/[\\s\\u3000]+/g, \"-\")\n // Unicode文字(L)・数字(N)・ハイフン以外を除去(記号や句読点など)\n .replace(/[^\\p{L}\\p{N}-]+/gu, \"\")\n // 先頭・末尾の余分なハイフンを除去\n .replace(/^-+|-+$/g, \"\");\n return slug || \"untitled-task\";\n}\n","import { spawn } from \"node:child_process\";\nimport path from \"node:path\";\nimport type { CommandStep, CommandExecutionResult, TaskRecord } from \"./types.js\";\n\nconst TIMEOUT_MS = 30_000;\n\nconst VARIABLE_PATTERN = /\\$\\{?(TASK_TITLE|TASK_FILEPATH|TASK_BODY)\\}?/g;\n\nexport function substituteVariables(command: string, vars: Record<string, string>): string {\n return command.replace(VARIABLE_PATTERN, (_match, name: string) => vars[name] ?? \"\");\n}\n\nexport async function executeCommandPipeline(\n rootDir: string,\n steps: CommandStep[],\n task: TaskRecord\n): Promise<CommandExecutionResult> {\n if (steps.length === 0) {\n return { stdout: \"\", stderr: \"\", exitCode: 0, duration: 0 };\n }\n\n const absoluteFilePath = path.resolve(rootDir, task.path);\n const vars: Record<string, string> = {\n TASK_TITLE: task.frontmatter.title,\n TASK_FILEPATH: absoluteFilePath,\n TASK_BODY: task.content\n };\n\n const startTime = Date.now();\n\n return new Promise<CommandExecutionResult>((resolve) => {\n const resolvedCommands = steps.map((step, index) => {\n let cmd = substituteVariables(step.command, vars);\n if (index === 0 && step.passBody === \"arg\") {\n const escaped = task.content.replace(/'/g, \"'\\\\''\");\n cmd = `${cmd} '${escaped}'`;\n }\n return cmd;\n });\n\n const processes: ReturnType<typeof spawn>[] = [];\n for (let index = 0; index < resolvedCommands.length; index++) {\n const proc = spawn(resolvedCommands[index], {\n shell: true,\n cwd: rootDir,\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n\n // pipe stdout of previous process to stdin of current\n if (index > 0) {\n const prev = processes[index - 1];\n if (prev?.stdout) {\n prev.stdout.pipe(proc.stdin!);\n }\n }\n\n processes.push(proc);\n }\n\n // Handle first command's passBody option\n const firstStep = steps[0];\n const firstProc = processes[0];\n if (firstStep.passBody === \"stdin\" && firstProc.stdin) {\n firstProc.stdin.write(task.content);\n }\n // Always close first process stdin (body written above if passBody is stdin)\n firstProc.stdin?.end();\n\n const lastProc = processes[processes.length - 1];\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n lastProc.stdout?.on(\"data\", (chunk: Buffer) => stdoutChunks.push(chunk));\n lastProc.stderr?.on(\"data\", (chunk: Buffer) => stderrChunks.push(chunk));\n\n // Collect stderr from all intermediate processes too\n for (let i = 0; i < processes.length - 1; i++) {\n processes[i].stderr?.on(\"data\", (chunk: Buffer) => stderrChunks.push(chunk));\n }\n\n const timeout = setTimeout(() => {\n for (const proc of processes) {\n proc.kill(\"SIGTERM\");\n }\n }, TIMEOUT_MS);\n\n lastProc.on(\"close\", (code) => {\n clearTimeout(timeout);\n resolve({\n stdout: Buffer.concat(stdoutChunks).toString(\"utf8\"),\n stderr: Buffer.concat(stderrChunks).toString(\"utf8\"),\n exitCode: code ?? 1,\n duration: Date.now() - startTime\n });\n });\n\n lastProc.on(\"error\", (err) => {\n clearTimeout(timeout);\n resolve({\n stdout: \"\",\n stderr: err.message,\n exitCode: 1,\n duration: Date.now() - startTime\n });\n });\n\n // Handle errors on intermediate processes\n for (let i = 0; i < processes.length - 1; i++) {\n processes[i].on(\"error\", (err) => {\n stderrChunks.push(Buffer.from(err.message));\n });\n }\n });\n}\n"],"mappings":"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","names":["path","path","path"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "md-task-viewer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Launch a local task viewer/editor for markdown files with frontmatter",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -35,31 +35,34 @@
|
|
|
35
35
|
"test:e2e": "playwright test"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
38
|
-
"node": ">=
|
|
38
|
+
"node": ">=24.0.0"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@dnd-kit/core": "^6.3.1",
|
|
42
42
|
"@dnd-kit/sortable": "^10.0.0",
|
|
43
43
|
"@dnd-kit/utilities": "^3.2.2",
|
|
44
|
-
"@fastify/static": "^
|
|
45
|
-
"chokidar": "^
|
|
46
|
-
"fastify": "^5.
|
|
44
|
+
"@fastify/static": "^9.0.0",
|
|
45
|
+
"chokidar": "^5.0.0",
|
|
46
|
+
"fastify": "^5.8.4",
|
|
47
47
|
"gray-matter": "^4.0.3",
|
|
48
|
-
"open": "^
|
|
49
|
-
"picomatch": "^4.0.
|
|
48
|
+
"open": "^11.0.0",
|
|
49
|
+
"picomatch": "^4.0.4",
|
|
50
50
|
"react": "^19.0.0",
|
|
51
51
|
"react-dom": "^19.0.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@playwright/test": "^1.52.0",
|
|
55
|
-
"@types/
|
|
55
|
+
"@types/dompurify": "^3.0.5",
|
|
56
|
+
"@types/node": "^24.0.0",
|
|
56
57
|
"@types/picomatch": "^4.0.2",
|
|
57
58
|
"@types/react": "^19.0.10",
|
|
58
59
|
"@types/react-dom": "^19.0.4",
|
|
59
|
-
"@vitejs/plugin-react": "^
|
|
60
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
61
|
+
"dompurify": "^3.3.3",
|
|
62
|
+
"marked": "^17.0.5",
|
|
60
63
|
"tsup": "^8.4.0",
|
|
61
|
-
"typescript": "^5.
|
|
62
|
-
"vite": "^
|
|
63
|
-
"vitest": "^
|
|
64
|
+
"typescript": "^5.9.3",
|
|
65
|
+
"vite": "^8.0.3",
|
|
66
|
+
"vitest": "^4.1.2"
|
|
64
67
|
}
|
|
65
68
|
}
|