From 1b2569a7a383d542b9f3b235e21ca6b1bb4ef8e6 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Jun 2026 17:49:00 +0000 Subject: [PATCH 1/4] feat(core-file-discovery): implement recursive .md file discovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds discoverMarkdownFiles(in:) to Core — enumerates a directory tree using FileManager, skips hidden directories via .skipsHiddenFiles, filters for .md files, and returns results sorted alphabetically by path. Throws DiscoveryError.notADirectory if the given URL is not a directory. https://claude.ai/code/session_01BuCBWNQyhdp6BGmAQXik5L --- Sources/Core/FileDiscovery.swift | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Sources/Core/FileDiscovery.swift diff --git a/Sources/Core/FileDiscovery.swift b/Sources/Core/FileDiscovery.swift new file mode 100644 index 0000000..d74c2b4 --- /dev/null +++ b/Sources/Core/FileDiscovery.swift @@ -0,0 +1,29 @@ +import Foundation + +public enum DiscoveryError: Error { + case notADirectory(URL) +} + +public func discoverMarkdownFiles(in directoryURL: URL) throws -> [URL] { + var isDirectory: ObjCBool = false + guard FileManager.default.fileExists(atPath: directoryURL.path, isDirectory: &isDirectory), + isDirectory.boolValue else { + throw DiscoveryError.notADirectory(directoryURL) + } + + let enumerator = FileManager.default.enumerator( + at: directoryURL, + includingPropertiesForKeys: [.isDirectoryKey], + options: [.skipsHiddenFiles] + ) + + var results: [URL] = [] + while let url = enumerator?.nextObject() as? URL { + let values = try? url.resourceValues(forKeys: [.isDirectoryKey]) + if values?.isDirectory == false, url.pathExtension == "md" { + results.append(url) + } + } + + return results.sorted { $0.path < $1.path } +} From 8d8371713028fc447ecd3c2779648d943cc01f47 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Jun 2026 17:49:53 +0000 Subject: [PATCH 2/4] =?UTF-8?q?chore(tasklin):=20move=20ticket=20ec0653c4?= =?UTF-8?q?=20through=20In=20Progress=20=E2=86=92=20Done?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://claude.ai/code/session_01BuCBWNQyhdp6BGmAQXik5L --- .todo/tickets/ec0653c4.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.todo/tickets/ec0653c4.yaml b/.todo/tickets/ec0653c4.yaml index b40ca7a..085810c 100644 --- a/.todo/tickets/ec0653c4.yaml +++ b/.todo/tickets/ec0653c4.yaml @@ -1,4 +1,11 @@ id: ec0653c4 title: Implement recursive .md file discovery (core-file-discovery TASK-01) -status: To Do +status: Done created_at: 2026-06-05T02:38:57.826481921Z +transitions: + - from: To Do + to: In Progress + at: 2026-06-06T17:48:09.34035645Z + - from: In Progress + to: Done + at: 2026-06-06T17:49:37.974735989Z From 7ba5a4a9a247559c3ec01fd2007ad0571e25f373 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Jun 2026 17:55:14 +0000 Subject: [PATCH 3/4] feat(core-file-discovery): define FileNode model Adds FileNode indirect enum to Core with file and directory cases. Conforms to Equatable (synthesised) and Identifiable (id: URL). Exposes name and path computed properties for uniform access across cases. https://claude.ai/code/session_01BuCBWNQyhdp6BGmAQXik5L --- Sources/Core/FileNode.swift | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Sources/Core/FileNode.swift diff --git a/Sources/Core/FileNode.swift b/Sources/Core/FileNode.swift new file mode 100644 index 0000000..5b749e2 --- /dev/null +++ b/Sources/Core/FileNode.swift @@ -0,0 +1,22 @@ +import Foundation + +public indirect enum FileNode: Equatable, Identifiable { + case file(name: String, path: URL) + case directory(name: String, path: URL, children: [FileNode]) + + public var id: URL { path } + + public var name: String { + switch self { + case .file(let name, _): return name + case .directory(let name, _, _): return name + } + } + + public var path: URL { + switch self { + case .file(_, let path): return path + case .directory(_, let path, _): return path + } + } +} From f911a809256170c5c68d60d671b5143e8dba0370 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Jun 2026 17:55:42 +0000 Subject: [PATCH 4/4] =?UTF-8?q?chore(tasklin):=20move=20ticket=2095eb1fe7?= =?UTF-8?q?=20through=20In=20Progress=20=E2=86=92=20Done?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://claude.ai/code/session_01BuCBWNQyhdp6BGmAQXik5L --- .todo/tickets/95eb1fe7.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.todo/tickets/95eb1fe7.yaml b/.todo/tickets/95eb1fe7.yaml index da4b1e3..ee3110d 100644 --- a/.todo/tickets/95eb1fe7.yaml +++ b/.todo/tickets/95eb1fe7.yaml @@ -1,4 +1,11 @@ id: 95eb1fe7 title: Define FileNode model (core-file-discovery TASK-02) -status: To Do +status: Done created_at: 2026-06-05T02:38:57.829857104Z +transitions: + - from: To Do + to: In Progress + at: 2026-06-06T17:54:43.8554997Z + - from: In Progress + to: Done + at: 2026-06-06T17:55:42.363318717Z