@stoneforge/quarry 1.12.0 → 1.14.0
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 +2 -0
- package/dist/api/quarry-api.d.ts +9 -1
- package/dist/api/quarry-api.d.ts.map +1 -1
- package/dist/api/quarry-api.js +21 -2
- package/dist/api/quarry-api.js.map +1 -1
- package/dist/api/types.d.ts +8 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/types.js.map +1 -1
- package/dist/cli/commands/auto-link-helper.d.ts +33 -0
- package/dist/cli/commands/auto-link-helper.d.ts.map +1 -0
- package/dist/cli/commands/auto-link-helper.js +74 -0
- package/dist/cli/commands/auto-link-helper.js.map +1 -0
- package/dist/cli/commands/crud.d.ts +3 -0
- package/dist/cli/commands/crud.d.ts.map +1 -1
- package/dist/cli/commands/crud.js +144 -15
- package/dist/cli/commands/crud.js.map +1 -1
- package/dist/cli/commands/docs.js +2 -2
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/document.js +1 -1
- package/dist/cli/commands/document.js.map +1 -1
- package/dist/cli/commands/entity.js +1 -1
- package/dist/cli/commands/entity.js.map +1 -1
- package/dist/cli/commands/external-sync.d.ts +18 -0
- package/dist/cli/commands/external-sync.d.ts.map +1 -0
- package/dist/cli/commands/external-sync.js +2499 -0
- package/dist/cli/commands/external-sync.js.map +1 -0
- package/dist/cli/commands/library.js +1 -1
- package/dist/cli/commands/library.js.map +1 -1
- package/dist/cli/commands/message.js +2 -2
- package/dist/cli/commands/message.js.map +1 -1
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/serve.js +2 -0
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli/commands/task.d.ts.map +1 -1
- package/dist/cli/commands/task.js +7 -4
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/commands/team.js +1 -1
- package/dist/cli/commands/team.js.map +1 -1
- package/dist/cli/commands/workflow.js +1 -1
- package/dist/cli/commands/workflow.js.map +1 -1
- package/dist/cli/runner.d.ts.map +1 -1
- package/dist/cli/runner.js +3 -0
- package/dist/cli/runner.js.map +1 -1
- package/dist/cli/utils/progress.d.ts +30 -0
- package/dist/cli/utils/progress.d.ts.map +1 -0
- package/dist/cli/utils/progress.js +47 -0
- package/dist/cli/utils/progress.js.map +1 -0
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +34 -0
- package/dist/config/config.js.map +1 -1
- package/dist/config/defaults.d.ts +13 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +22 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/file.d.ts.map +1 -1
- package/dist/config/file.js +71 -0
- package/dist/config/file.js.map +1 -1
- package/dist/config/index.d.ts +3 -3
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +2 -2
- package/dist/config/index.js.map +1 -1
- package/dist/config/merge.d.ts.map +1 -1
- package/dist/config/merge.js +52 -1
- package/dist/config/merge.js.map +1 -1
- package/dist/config/types.d.ts +68 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +33 -0
- package/dist/config/types.js.map +1 -1
- package/dist/config/validation.d.ts.map +1 -1
- package/dist/config/validation.js +64 -1
- package/dist/config/validation.js.map +1 -1
- package/dist/external-sync/adapters/document-sync-adapter.d.ts +150 -0
- package/dist/external-sync/adapters/document-sync-adapter.d.ts.map +1 -0
- package/dist/external-sync/adapters/document-sync-adapter.js +325 -0
- package/dist/external-sync/adapters/document-sync-adapter.js.map +1 -0
- package/dist/external-sync/adapters/task-sync-adapter.d.ts +177 -0
- package/dist/external-sync/adapters/task-sync-adapter.d.ts.map +1 -0
- package/dist/external-sync/adapters/task-sync-adapter.js +353 -0
- package/dist/external-sync/adapters/task-sync-adapter.js.map +1 -0
- package/dist/external-sync/auto-link.d.ts +66 -0
- package/dist/external-sync/auto-link.d.ts.map +1 -0
- package/dist/external-sync/auto-link.js +98 -0
- package/dist/external-sync/auto-link.js.map +1 -0
- package/dist/external-sync/conflict-resolver.d.ts +170 -0
- package/dist/external-sync/conflict-resolver.d.ts.map +1 -0
- package/dist/external-sync/conflict-resolver.js +580 -0
- package/dist/external-sync/conflict-resolver.js.map +1 -0
- package/dist/external-sync/index.d.ts +23 -0
- package/dist/external-sync/index.d.ts.map +1 -0
- package/dist/external-sync/index.js +24 -0
- package/dist/external-sync/index.js.map +1 -0
- package/dist/external-sync/provider-registry.d.ts +113 -0
- package/dist/external-sync/provider-registry.d.ts.map +1 -0
- package/dist/external-sync/provider-registry.js +205 -0
- package/dist/external-sync/provider-registry.js.map +1 -0
- package/dist/external-sync/providers/folder/folder-document-adapter.d.ts +97 -0
- package/dist/external-sync/providers/folder/folder-document-adapter.d.ts.map +1 -0
- package/dist/external-sync/providers/folder/folder-document-adapter.js +261 -0
- package/dist/external-sync/providers/folder/folder-document-adapter.js.map +1 -0
- package/dist/external-sync/providers/folder/folder-fs.d.ts +146 -0
- package/dist/external-sync/providers/folder/folder-fs.d.ts.map +1 -0
- package/dist/external-sync/providers/folder/folder-fs.js +300 -0
- package/dist/external-sync/providers/folder/folder-fs.js.map +1 -0
- package/dist/external-sync/providers/folder/folder-provider.d.ts +28 -0
- package/dist/external-sync/providers/folder/folder-provider.d.ts.map +1 -0
- package/dist/external-sync/providers/folder/folder-provider.js +87 -0
- package/dist/external-sync/providers/folder/folder-provider.js.map +1 -0
- package/dist/external-sync/providers/folder/index.d.ts +11 -0
- package/dist/external-sync/providers/folder/index.d.ts.map +1 -0
- package/dist/external-sync/providers/folder/index.js +13 -0
- package/dist/external-sync/providers/folder/index.js.map +1 -0
- package/dist/external-sync/providers/github/github-api.d.ts +271 -0
- package/dist/external-sync/providers/github/github-api.d.ts.map +1 -0
- package/dist/external-sync/providers/github/github-api.js +366 -0
- package/dist/external-sync/providers/github/github-api.js.map +1 -0
- package/dist/external-sync/providers/github/github-field-map.d.ts +76 -0
- package/dist/external-sync/providers/github/github-field-map.d.ts.map +1 -0
- package/dist/external-sync/providers/github/github-field-map.js +157 -0
- package/dist/external-sync/providers/github/github-field-map.js.map +1 -0
- package/dist/external-sync/providers/github/github-provider.d.ts +36 -0
- package/dist/external-sync/providers/github/github-provider.d.ts.map +1 -0
- package/dist/external-sync/providers/github/github-provider.js +212 -0
- package/dist/external-sync/providers/github/github-provider.js.map +1 -0
- package/dist/external-sync/providers/github/github-task-adapter.d.ts +135 -0
- package/dist/external-sync/providers/github/github-task-adapter.d.ts.map +1 -0
- package/dist/external-sync/providers/github/github-task-adapter.js +374 -0
- package/dist/external-sync/providers/github/github-task-adapter.js.map +1 -0
- package/dist/external-sync/providers/github/index.d.ts +12 -0
- package/dist/external-sync/providers/github/index.d.ts.map +1 -0
- package/dist/external-sync/providers/github/index.js +15 -0
- package/dist/external-sync/providers/github/index.js.map +1 -0
- package/dist/external-sync/providers/index.d.ts +13 -0
- package/dist/external-sync/providers/index.d.ts.map +1 -0
- package/dist/external-sync/providers/index.js +15 -0
- package/dist/external-sync/providers/index.js.map +1 -0
- package/dist/external-sync/providers/linear/index.d.ts +19 -0
- package/dist/external-sync/providers/linear/index.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/index.js +19 -0
- package/dist/external-sync/providers/linear/index.js.map +1 -0
- package/dist/external-sync/providers/linear/linear-api.d.ts +252 -0
- package/dist/external-sync/providers/linear/linear-api.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/linear-api.js +522 -0
- package/dist/external-sync/providers/linear/linear-api.js.map +1 -0
- package/dist/external-sync/providers/linear/linear-field-map.d.ts +135 -0
- package/dist/external-sync/providers/linear/linear-field-map.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/linear-field-map.js +338 -0
- package/dist/external-sync/providers/linear/linear-field-map.js.map +1 -0
- package/dist/external-sync/providers/linear/linear-provider.d.ts +52 -0
- package/dist/external-sync/providers/linear/linear-provider.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/linear-provider.js +169 -0
- package/dist/external-sync/providers/linear/linear-provider.js.map +1 -0
- package/dist/external-sync/providers/linear/linear-task-adapter.d.ts +190 -0
- package/dist/external-sync/providers/linear/linear-task-adapter.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/linear-task-adapter.js +521 -0
- package/dist/external-sync/providers/linear/linear-task-adapter.js.map +1 -0
- package/dist/external-sync/providers/linear/linear-types.d.ts +114 -0
- package/dist/external-sync/providers/linear/linear-types.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/linear-types.js +10 -0
- package/dist/external-sync/providers/linear/linear-types.js.map +1 -0
- package/dist/external-sync/providers/notion/index.d.ts +19 -0
- package/dist/external-sync/providers/notion/index.d.ts.map +1 -0
- package/dist/external-sync/providers/notion/index.js +20 -0
- package/dist/external-sync/providers/notion/index.js.map +1 -0
- package/dist/external-sync/providers/notion/notion-api.d.ts +253 -0
- package/dist/external-sync/providers/notion/notion-api.d.ts.map +1 -0
- package/dist/external-sync/providers/notion/notion-api.js +492 -0
- package/dist/external-sync/providers/notion/notion-api.js.map +1 -0
- package/dist/external-sync/providers/notion/notion-blocks.d.ts +93 -0
- package/dist/external-sync/providers/notion/notion-blocks.d.ts.map +1 -0
- package/dist/external-sync/providers/notion/notion-blocks.js +773 -0
- package/dist/external-sync/providers/notion/notion-blocks.js.map +1 -0
- package/dist/external-sync/providers/notion/notion-document-adapter.d.ts +176 -0
- package/dist/external-sync/providers/notion/notion-document-adapter.d.ts.map +1 -0
- package/dist/external-sync/providers/notion/notion-document-adapter.js +413 -0
- package/dist/external-sync/providers/notion/notion-document-adapter.js.map +1 -0
- package/dist/external-sync/providers/notion/notion-provider.d.ts +57 -0
- package/dist/external-sync/providers/notion/notion-provider.d.ts.map +1 -0
- package/dist/external-sync/providers/notion/notion-provider.js +159 -0
- package/dist/external-sync/providers/notion/notion-provider.js.map +1 -0
- package/dist/external-sync/providers/notion/notion-types.d.ts +388 -0
- package/dist/external-sync/providers/notion/notion-types.d.ts.map +1 -0
- package/dist/external-sync/providers/notion/notion-types.js +47 -0
- package/dist/external-sync/providers/notion/notion-types.js.map +1 -0
- package/dist/external-sync/sync-engine.d.ts +364 -0
- package/dist/external-sync/sync-engine.d.ts.map +1 -0
- package/dist/external-sync/sync-engine.js +1154 -0
- package/dist/external-sync/sync-engine.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/server/index.js +8 -8
- package/dist/server/index.js.map +1 -1
- package/dist/services/inbox.js +1 -1
- package/dist/sync/hash.d.ts +5 -0
- package/dist/sync/hash.d.ts.map +1 -1
- package/dist/sync/hash.js +21 -2
- package/dist/sync/hash.js.map +1 -1
- package/package.json +10 -12
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folder Filesystem Client
|
|
3
|
+
*
|
|
4
|
+
* Filesystem layer for the folder sync provider. Reads, writes, and lists
|
|
5
|
+
* markdown files with YAML frontmatter in a local directory tree.
|
|
6
|
+
*
|
|
7
|
+
* Follows the same API client pattern as github-api.ts — a focused,
|
|
8
|
+
* dependency-light module that handles I/O for a single provider.
|
|
9
|
+
*
|
|
10
|
+
* Uses the `yaml` package for frontmatter parsing/serialization.
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'node:fs';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import * as yaml from 'yaml';
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Error Types
|
|
17
|
+
// ============================================================================
|
|
18
|
+
/**
|
|
19
|
+
* Typed error for folder filesystem failures.
|
|
20
|
+
*/
|
|
21
|
+
export class FolderFsError extends Error {
|
|
22
|
+
/** The operation that failed */
|
|
23
|
+
operation;
|
|
24
|
+
/** The file path involved (if applicable) */
|
|
25
|
+
filePath;
|
|
26
|
+
/** The underlying system error code (e.g., 'ENOENT', 'EACCES') */
|
|
27
|
+
code;
|
|
28
|
+
constructor(message, operation, filePath = null, code = null, cause) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.name = 'FolderFsError';
|
|
31
|
+
this.operation = operation;
|
|
32
|
+
this.filePath = filePath;
|
|
33
|
+
this.code = code;
|
|
34
|
+
this.cause = cause;
|
|
35
|
+
if (Error.captureStackTrace) {
|
|
36
|
+
Error.captureStackTrace(this, FolderFsError);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Whether this error is due to a missing file or directory
|
|
41
|
+
*/
|
|
42
|
+
get isNotFound() {
|
|
43
|
+
return this.code === 'ENOENT';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Whether this error is due to a permission issue
|
|
47
|
+
*/
|
|
48
|
+
get isPermissionError() {
|
|
49
|
+
return this.code === 'EACCES' || this.code === 'EPERM';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Type guard for FolderFsError
|
|
54
|
+
*/
|
|
55
|
+
export function isFolderFsError(error) {
|
|
56
|
+
return error instanceof FolderFsError;
|
|
57
|
+
}
|
|
58
|
+
// ============================================================================
|
|
59
|
+
// Frontmatter Parsing / Serialization
|
|
60
|
+
// ============================================================================
|
|
61
|
+
/** Frontmatter delimiter */
|
|
62
|
+
const FRONTMATTER_DELIMITER = '---';
|
|
63
|
+
/**
|
|
64
|
+
* Parses YAML frontmatter from a markdown string.
|
|
65
|
+
*
|
|
66
|
+
* Expects the standard `---` delimited frontmatter block at the start of the file.
|
|
67
|
+
* Returns the body content and parsed frontmatter separately.
|
|
68
|
+
*
|
|
69
|
+
* @param raw - Raw file content (may or may not have frontmatter)
|
|
70
|
+
* @returns Parsed frontmatter and body content
|
|
71
|
+
*/
|
|
72
|
+
export function parseFrontmatter(raw) {
|
|
73
|
+
const trimmed = raw.trimStart();
|
|
74
|
+
if (!trimmed.startsWith(FRONTMATTER_DELIMITER)) {
|
|
75
|
+
return { content: raw, frontmatter: {} };
|
|
76
|
+
}
|
|
77
|
+
// Find the closing delimiter
|
|
78
|
+
const afterOpening = trimmed.indexOf('\n');
|
|
79
|
+
if (afterOpening === -1) {
|
|
80
|
+
return { content: raw, frontmatter: {} };
|
|
81
|
+
}
|
|
82
|
+
const rest = trimmed.slice(afterOpening + 1);
|
|
83
|
+
// Check for closing delimiter: could be at the very start (empty frontmatter)
|
|
84
|
+
// or after a newline
|
|
85
|
+
let closingIndex;
|
|
86
|
+
let yamlBlock;
|
|
87
|
+
if (rest.startsWith(FRONTMATTER_DELIMITER)) {
|
|
88
|
+
// Empty frontmatter block: ---\n---
|
|
89
|
+
closingIndex = 0;
|
|
90
|
+
yamlBlock = '';
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const nlClosing = rest.indexOf(`\n${FRONTMATTER_DELIMITER}`);
|
|
94
|
+
if (nlClosing === -1) {
|
|
95
|
+
// No closing delimiter found — treat entire file as content
|
|
96
|
+
return { content: raw, frontmatter: {} };
|
|
97
|
+
}
|
|
98
|
+
closingIndex = nlClosing + 1; // point to the start of ---
|
|
99
|
+
yamlBlock = rest.slice(0, nlClosing);
|
|
100
|
+
}
|
|
101
|
+
// Content starts after the closing delimiter line
|
|
102
|
+
const closingLineEnd = rest.indexOf('\n', closingIndex);
|
|
103
|
+
const body = closingLineEnd === -1 ? '' : rest.slice(closingLineEnd + 1);
|
|
104
|
+
let parsed;
|
|
105
|
+
try {
|
|
106
|
+
parsed = yaml.parse(yamlBlock);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// If YAML is malformed, treat the whole file as content
|
|
110
|
+
return { content: raw, frontmatter: {} };
|
|
111
|
+
}
|
|
112
|
+
// yaml.parse can return null for empty YAML blocks
|
|
113
|
+
const frontmatter = parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
114
|
+
? parsed
|
|
115
|
+
: {};
|
|
116
|
+
return { content: body, frontmatter };
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Serializes frontmatter and content into a markdown string with YAML front matter.
|
|
120
|
+
*
|
|
121
|
+
* @param content - Markdown body content
|
|
122
|
+
* @param frontmatter - Frontmatter key-value pairs
|
|
123
|
+
* @returns Complete file content with frontmatter block
|
|
124
|
+
*/
|
|
125
|
+
export function serializeFrontmatter(content, frontmatter) {
|
|
126
|
+
const hasFields = Object.keys(frontmatter).length > 0;
|
|
127
|
+
if (!hasFields) {
|
|
128
|
+
return content;
|
|
129
|
+
}
|
|
130
|
+
const yamlStr = yaml.stringify(frontmatter, {
|
|
131
|
+
lineWidth: 0, // Don't wrap lines
|
|
132
|
+
}).trimEnd();
|
|
133
|
+
return `${FRONTMATTER_DELIMITER}\n${yamlStr}\n${FRONTMATTER_DELIMITER}\n${content}`;
|
|
134
|
+
}
|
|
135
|
+
// ============================================================================
|
|
136
|
+
// Filesystem Operations
|
|
137
|
+
// ============================================================================
|
|
138
|
+
/**
|
|
139
|
+
* Reads a markdown file with YAML frontmatter from a folder.
|
|
140
|
+
*
|
|
141
|
+
* @param basePath - Absolute path to the base directory
|
|
142
|
+
* @param relativePath - Path relative to basePath (e.g., 'notes/meeting.md')
|
|
143
|
+
* @returns Parsed file content, frontmatter, and modification time
|
|
144
|
+
* @throws {FolderFsError} If the file cannot be read
|
|
145
|
+
*/
|
|
146
|
+
export async function readFile(basePath, relativePath) {
|
|
147
|
+
const fullPath = path.resolve(basePath, relativePath);
|
|
148
|
+
// Security: ensure the resolved path is within basePath
|
|
149
|
+
const resolvedBase = path.resolve(basePath);
|
|
150
|
+
if (!fullPath.startsWith(resolvedBase + path.sep) && fullPath !== resolvedBase) {
|
|
151
|
+
throw new FolderFsError(`Path traversal detected: "${relativePath}" resolves outside base directory`, 'read', relativePath, 'EACCES');
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
const [raw, stat] = await Promise.all([
|
|
155
|
+
fs.promises.readFile(fullPath, 'utf-8'),
|
|
156
|
+
fs.promises.stat(fullPath),
|
|
157
|
+
]);
|
|
158
|
+
const { content, frontmatter } = parseFrontmatter(raw);
|
|
159
|
+
return {
|
|
160
|
+
content,
|
|
161
|
+
frontmatter,
|
|
162
|
+
mtime: stat.mtimeMs,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
const sysErr = err;
|
|
167
|
+
throw new FolderFsError(`Failed to read file "${relativePath}": ${sysErr.message}`, 'read', relativePath, sysErr.code ?? null, sysErr);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Writes a markdown file with YAML frontmatter to a folder.
|
|
172
|
+
*
|
|
173
|
+
* Writes atomically by first writing to a temporary file in the same directory,
|
|
174
|
+
* then renaming. This prevents partial writes from corrupting files.
|
|
175
|
+
*
|
|
176
|
+
* @param basePath - Absolute path to the base directory
|
|
177
|
+
* @param relativePath - Path relative to basePath (e.g., 'notes/meeting.md')
|
|
178
|
+
* @param content - Markdown body content
|
|
179
|
+
* @param frontmatter - YAML frontmatter key-value pairs
|
|
180
|
+
* @throws {FolderFsError} If the file cannot be written
|
|
181
|
+
*/
|
|
182
|
+
export async function writeFile(basePath, relativePath, content, frontmatter) {
|
|
183
|
+
const fullPath = path.resolve(basePath, relativePath);
|
|
184
|
+
// Security: ensure the resolved path is within basePath
|
|
185
|
+
const resolvedBase = path.resolve(basePath);
|
|
186
|
+
if (!fullPath.startsWith(resolvedBase + path.sep) && fullPath !== resolvedBase) {
|
|
187
|
+
throw new FolderFsError(`Path traversal detected: "${relativePath}" resolves outside base directory`, 'write', relativePath, 'EACCES');
|
|
188
|
+
}
|
|
189
|
+
const serialized = serializeFrontmatter(content, frontmatter);
|
|
190
|
+
const dir = path.dirname(fullPath);
|
|
191
|
+
const tmpPath = `${fullPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
|
|
192
|
+
try {
|
|
193
|
+
// Ensure parent directories exist
|
|
194
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
195
|
+
// Write to temp file, then rename for atomicity
|
|
196
|
+
await fs.promises.writeFile(tmpPath, serialized, 'utf-8');
|
|
197
|
+
await fs.promises.rename(tmpPath, fullPath);
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
// Clean up temp file on failure
|
|
201
|
+
try {
|
|
202
|
+
await fs.promises.unlink(tmpPath);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
// Ignore cleanup errors
|
|
206
|
+
}
|
|
207
|
+
const sysErr = err;
|
|
208
|
+
throw new FolderFsError(`Failed to write file "${relativePath}": ${sysErr.message}`, 'write', relativePath, sysErr.code ?? null, sysErr);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Recursively lists all `.md` files in a directory tree.
|
|
213
|
+
*
|
|
214
|
+
* Excludes:
|
|
215
|
+
* - Dotfiles (files starting with `.`)
|
|
216
|
+
* - Files inside dot-directories (directories starting with `.`)
|
|
217
|
+
*
|
|
218
|
+
* @param basePath - Absolute path to the base directory
|
|
219
|
+
* @param options - Optional filtering (e.g., `since` timestamp)
|
|
220
|
+
* @returns Array of file entries with relative paths and modification times
|
|
221
|
+
* @throws {FolderFsError} If the directory cannot be read
|
|
222
|
+
*/
|
|
223
|
+
export async function listFiles(basePath, options) {
|
|
224
|
+
const resolvedBase = path.resolve(basePath);
|
|
225
|
+
const entries = [];
|
|
226
|
+
try {
|
|
227
|
+
await walkDirectory(resolvedBase, resolvedBase, entries, options?.since);
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
const sysErr = err;
|
|
231
|
+
throw new FolderFsError(`Failed to list files in "${basePath}": ${sysErr.message}`, 'list', null, sysErr.code ?? null, sysErr);
|
|
232
|
+
}
|
|
233
|
+
// Sort by path for deterministic output
|
|
234
|
+
entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
235
|
+
return entries;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Checks whether a file exists at the given relative path within a base directory.
|
|
239
|
+
*
|
|
240
|
+
* @param basePath - Absolute path to the base directory
|
|
241
|
+
* @param relativePath - Path relative to basePath (e.g., 'notes/meeting.md')
|
|
242
|
+
* @returns True if the file exists, false otherwise
|
|
243
|
+
*/
|
|
244
|
+
export async function fileExists(basePath, relativePath) {
|
|
245
|
+
try {
|
|
246
|
+
await fs.promises.access(path.join(basePath, relativePath));
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// ============================================================================
|
|
254
|
+
// Internal Helpers
|
|
255
|
+
// ============================================================================
|
|
256
|
+
/**
|
|
257
|
+
* Recursively walks a directory tree, collecting .md files.
|
|
258
|
+
*
|
|
259
|
+
* @param currentDir - Current directory being scanned
|
|
260
|
+
* @param baseDir - Root base directory (for computing relative paths)
|
|
261
|
+
* @param results - Accumulator array for found entries
|
|
262
|
+
* @param since - Optional mtime filter (milliseconds)
|
|
263
|
+
*/
|
|
264
|
+
async function walkDirectory(currentDir, baseDir, results, since) {
|
|
265
|
+
const dirEntries = await fs.promises.readdir(currentDir, {
|
|
266
|
+
withFileTypes: true,
|
|
267
|
+
});
|
|
268
|
+
const promises = [];
|
|
269
|
+
for (const entry of dirEntries) {
|
|
270
|
+
const name = entry.name;
|
|
271
|
+
// Skip dotfiles and dot-directories
|
|
272
|
+
if (name.startsWith('.')) {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const fullPath = path.join(currentDir, name);
|
|
276
|
+
if (entry.isDirectory()) {
|
|
277
|
+
// Recurse into subdirectories
|
|
278
|
+
promises.push(walkDirectory(fullPath, baseDir, results, since));
|
|
279
|
+
}
|
|
280
|
+
else if (entry.isFile() && name.endsWith('.md')) {
|
|
281
|
+
// Collect .md files
|
|
282
|
+
promises.push((async () => {
|
|
283
|
+
const stat = await fs.promises.stat(fullPath);
|
|
284
|
+
const mtime = stat.mtimeMs;
|
|
285
|
+
// Apply since filter
|
|
286
|
+
if (since !== undefined && mtime <= since) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
// Compute relative path with forward slashes
|
|
290
|
+
const relativePath = path
|
|
291
|
+
.relative(baseDir, fullPath)
|
|
292
|
+
.split(path.sep)
|
|
293
|
+
.join('/');
|
|
294
|
+
results.push({ path: relativePath, mtime });
|
|
295
|
+
})());
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
await Promise.all(promises);
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=folder-fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folder-fs.js","sourceRoot":"","sources":["../../../../src/external-sync/providers/folder/folder-fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAwD7B,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E;;GAEG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,gCAAgC;IACvB,SAAS,CAA4B;IAC9C,6CAA6C;IACpC,QAAQ,CAAgB;IACjC,kEAAkE;IACzD,IAAI,CAAgB;IAE7B,YACE,OAAe,EACf,SAAoC,EACpC,WAA0B,IAAI,EAC9B,OAAsB,IAAI,EAC1B,KAAa;QAEb,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QAEnB,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED;;OAEG;IACH,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,IAAI,iBAAiB;QACnB,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC;IACzD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,KAAK,YAAY,aAAa,CAAC;AACxC,CAAC;AAED,+EAA+E;AAC/E,sCAAsC;AACtC,+EAA+E;AAE/E,4BAA4B;AAC5B,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAI1C,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;IAEhC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,6BAA6B;IAC7B,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;IAE7C,8EAA8E;IAC9E,qBAAqB;IACrB,IAAI,YAAoB,CAAC;IACzB,IAAI,SAAiB,CAAC;IAEtB,IAAI,IAAI,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAC3C,oCAAoC;QACpC,YAAY,GAAG,CAAC,CAAC;QACjB,SAAS,GAAG,EAAE,CAAC;IACjB,CAAC;SAAM,CAAC;QACN,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,qBAAqB,EAAE,CAAC,CAAC;QAC7D,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;YACrB,4DAA4D;YAC5D,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;QAC3C,CAAC;QACD,YAAY,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,4BAA4B;QAC1D,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,kDAAkD;IAClD,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACxD,MAAM,IAAI,GACR,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC;IAE9D,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;QACxD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,mDAAmD;IACnD,MAAM,WAAW,GACf,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QACrE,CAAC,CAAE,MAA4B;QAC/B,CAAC,CAAC,EAAE,CAAC;IAET,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AACxC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAe,EACf,WAA8B;IAE9B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAEtD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;QAC1C,SAAS,EAAE,CAAC,EAAE,mBAAmB;KAClC,CAAC,CAAC,OAAO,EAAE,CAAC;IAEb,OAAO,GAAG,qBAAqB,KAAK,OAAO,KAAK,qBAAqB,KAAK,OAAO,EAAE,CAAC;AACtF,CAAC;AAED,+EAA+E;AAC/E,wBAAwB;AACxB,+EAA+E;AAE/E;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,QAAgB,EAChB,YAAoB;IAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEtD,wDAAwD;IACxD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC/E,MAAM,IAAI,aAAa,CACrB,6BAA6B,YAAY,mCAAmC,EAC5E,MAAM,EACN,YAAY,EACZ,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACpC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;YACvC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;SAC3B,CAAC,CAAC;QAEH,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAEvD,OAAO;YACL,OAAO;YACP,WAAW;YACX,KAAK,EAAE,IAAI,CAAC,OAAO;SACpB,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAA4B,CAAC;QAC5C,MAAM,IAAI,aAAa,CACrB,wBAAwB,YAAY,MAAM,MAAM,CAAC,OAAO,EAAE,EAC1D,MAAM,EACN,YAAY,EACZ,MAAM,CAAC,IAAI,IAAI,IAAI,EACnB,MAAM,CACP,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,QAAgB,EAChB,YAAoB,EACpB,OAAe,EACf,WAA8B;IAE9B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEtD,wDAAwD;IACxD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC/E,MAAM,IAAI,aAAa,CACrB,6BAA6B,YAAY,mCAAmC,EAC5E,OAAO,EACP,YAAY,EACZ,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,GAAG,QAAQ,QAAQ,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAE1F,IAAI,CAAC;QACH,kCAAkC;QAClC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAElD,gDAAgD;QAChD,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAC1D,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,gCAAgC;QAChC,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;QAED,MAAM,MAAM,GAAG,GAA4B,CAAC;QAC5C,MAAM,IAAI,aAAa,CACrB,yBAAyB,YAAY,MAAM,MAAM,CAAC,OAAO,EAAE,EAC3D,OAAO,EACP,YAAY,EACZ,MAAM,CAAC,IAAI,IAAI,IAAI,EACnB,MAAM,CACP,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,QAAgB,EAChB,OAA0B;IAE1B,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAC3E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAA4B,CAAC;QAC5C,MAAM,IAAI,aAAa,CACrB,4BAA4B,QAAQ,MAAM,MAAM,CAAC,OAAO,EAAE,EAC1D,MAAM,EACN,IAAI,EACJ,MAAM,CAAC,IAAI,IAAI,IAAI,EACnB,MAAM,CACP,CAAC;IACJ,CAAC;IAED,wCAAwC;IACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAErD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,QAAgB,EAChB,YAAoB;IAEpB,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E;;;;;;;GAOG;AACH,KAAK,UAAU,aAAa,CAC1B,UAAkB,EAClB,OAAe,EACf,OAA0B,EAC1B,KAAc;IAEd,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE;QACvD,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QAExB,oCAAoC;QACpC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,SAAS;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAE7C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,8BAA8B;YAC9B,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QAClE,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,oBAAoB;YACpB,QAAQ,CAAC,IAAI,CACX,CAAC,KAAK,IAAI,EAAE;gBACV,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC;gBAE3B,qBAAqB;gBACrB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;oBAC1C,OAAO;gBACT,CAAC;gBAED,6CAA6C;gBAC7C,MAAM,YAAY,GAAG,IAAI;qBACtB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;qBAC3B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;qBACf,IAAI,CAAC,GAAG,CAAC,CAAC;gBAEb,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9C,CAAC,CAAC,EAAE,CACL,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folder Provider
|
|
3
|
+
*
|
|
4
|
+
* ExternalProvider implementation for local folder-based document sync.
|
|
5
|
+
* No authentication needed — the project path (folder path) is the
|
|
6
|
+
* only configuration required.
|
|
7
|
+
*
|
|
8
|
+
* Provides a DocumentSyncAdapter for bidirectional synchronization
|
|
9
|
+
* between Stoneforge documents and markdown files on the local filesystem.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const provider = createFolderProvider();
|
|
14
|
+
* const connected = await provider.testConnection({ provider: 'folder', defaultProject: '/path/to/docs' });
|
|
15
|
+
* const adapter = provider.getDocumentAdapter();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import type { ExternalProvider } from '@stoneforge/core';
|
|
19
|
+
/**
|
|
20
|
+
* Create a folder provider for local filesystem document sync.
|
|
21
|
+
*
|
|
22
|
+
* The provider is always ready — no authentication or configuration
|
|
23
|
+
* beyond the folder path is needed.
|
|
24
|
+
*
|
|
25
|
+
* @returns A configured Folder ExternalProvider
|
|
26
|
+
*/
|
|
27
|
+
export declare function createFolderProvider(): ExternalProvider;
|
|
28
|
+
//# sourceMappingURL=folder-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folder-provider.d.ts","sourceRoot":"","sources":["../../../../src/external-sync/providers/folder/folder-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EACV,gBAAgB,EAIjB,MAAM,kBAAkB,CAAC;AAmE1B;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,IAAI,gBAAgB,CAEvD"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folder Provider
|
|
3
|
+
*
|
|
4
|
+
* ExternalProvider implementation for local folder-based document sync.
|
|
5
|
+
* No authentication needed — the project path (folder path) is the
|
|
6
|
+
* only configuration required.
|
|
7
|
+
*
|
|
8
|
+
* Provides a DocumentSyncAdapter for bidirectional synchronization
|
|
9
|
+
* between Stoneforge documents and markdown files on the local filesystem.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const provider = createFolderProvider();
|
|
14
|
+
* const connected = await provider.testConnection({ provider: 'folder', defaultProject: '/path/to/docs' });
|
|
15
|
+
* const adapter = provider.getDocumentAdapter();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import * as fs from 'node:fs';
|
|
19
|
+
import { FolderDocumentAdapter } from './folder-document-adapter.js';
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Folder Provider
|
|
22
|
+
// ============================================================================
|
|
23
|
+
/**
|
|
24
|
+
* Folder ExternalProvider implementation.
|
|
25
|
+
*
|
|
26
|
+
* Provides connection testing (checks if path exists and is a directory)
|
|
27
|
+
* and a DocumentSyncAdapter for local folder sync.
|
|
28
|
+
*
|
|
29
|
+
* No token is needed — the `defaultProject` field in ProviderConfig
|
|
30
|
+
* specifies the folder path to sync with.
|
|
31
|
+
*/
|
|
32
|
+
class FolderProvider {
|
|
33
|
+
name = 'folder';
|
|
34
|
+
displayName = 'Folder';
|
|
35
|
+
supportedAdapters = ['document'];
|
|
36
|
+
documentAdapter;
|
|
37
|
+
constructor() {
|
|
38
|
+
this.documentAdapter = new FolderDocumentAdapter();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Test whether the configured folder path exists and is a directory.
|
|
42
|
+
*
|
|
43
|
+
* Uses `defaultProject` from the config as the folder path.
|
|
44
|
+
* Returns false if no path is configured or the path doesn't exist
|
|
45
|
+
* or isn't a directory.
|
|
46
|
+
*
|
|
47
|
+
* @param config - Provider configuration with defaultProject as folder path
|
|
48
|
+
* @returns true if the path exists and is a directory, false otherwise
|
|
49
|
+
*/
|
|
50
|
+
async testConnection(config) {
|
|
51
|
+
const folderPath = config.defaultProject;
|
|
52
|
+
if (!folderPath) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const stat = await fs.promises.stat(folderPath);
|
|
57
|
+
return stat.isDirectory();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Path doesn't exist or can't be accessed
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns the FolderDocumentAdapter instance for document sync.
|
|
66
|
+
*
|
|
67
|
+
* @returns DocumentSyncAdapter for folder-based document sync
|
|
68
|
+
*/
|
|
69
|
+
getDocumentAdapter() {
|
|
70
|
+
return this.documentAdapter;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Factory Function
|
|
75
|
+
// ============================================================================
|
|
76
|
+
/**
|
|
77
|
+
* Create a folder provider for local filesystem document sync.
|
|
78
|
+
*
|
|
79
|
+
* The provider is always ready — no authentication or configuration
|
|
80
|
+
* beyond the folder path is needed.
|
|
81
|
+
*
|
|
82
|
+
* @returns A configured Folder ExternalProvider
|
|
83
|
+
*/
|
|
84
|
+
export function createFolderProvider() {
|
|
85
|
+
return new FolderProvider();
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=folder-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folder-provider.js","sourceRoot":"","sources":["../../../../src/external-sync/providers/folder/folder-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAQ9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,+EAA+E;AAC/E,kBAAkB;AAClB,+EAA+E;AAE/E;;;;;;;;GAQG;AACH,MAAM,cAAc;IACT,IAAI,GAAG,QAAQ,CAAC;IAChB,WAAW,GAAG,QAAQ,CAAC;IACvB,iBAAiB,GAA+B,CAAC,UAAU,CAAC,CAAC;IAErD,eAAe,CAAwB;IAExD;QACE,IAAI,CAAC,eAAe,GAAG,IAAI,qBAAqB,EAAE,CAAC;IACrD,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,cAAc,CAAC,MAAsB;QACzC,MAAM,UAAU,GAAG,MAAM,CAAC,cAAc,CAAC;QACzC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAChD,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;YAC1C,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,kBAAkB;QAChB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,IAAI,cAAc,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folder Provider — exports for the folder external sync provider
|
|
3
|
+
*
|
|
4
|
+
* Exports the folder provider factory, document adapter, and
|
|
5
|
+
* filesystem utilities.
|
|
6
|
+
*/
|
|
7
|
+
export { createFolderProvider } from './folder-provider.js';
|
|
8
|
+
export { FolderDocumentAdapter, createFolderDocumentAdapter, slugify, } from './folder-document-adapter.js';
|
|
9
|
+
export { readFile, writeFile, listFiles, parseFrontmatter, serializeFrontmatter, FolderFsError, isFolderFsError, } from './folder-fs.js';
|
|
10
|
+
export type { FolderFrontmatter, FolderFileReadResult, FolderFileEntry, ListFilesOptions, } from './folder-fs.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/external-sync/providers/folder/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG5D,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,OAAO,GACR,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACL,QAAQ,EACR,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,GACjB,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folder Provider — exports for the folder external sync provider
|
|
3
|
+
*
|
|
4
|
+
* Exports the folder provider factory, document adapter, and
|
|
5
|
+
* filesystem utilities.
|
|
6
|
+
*/
|
|
7
|
+
// Provider factory
|
|
8
|
+
export { createFolderProvider } from './folder-provider.js';
|
|
9
|
+
// Document adapter
|
|
10
|
+
export { FolderDocumentAdapter, createFolderDocumentAdapter, slugify, } from './folder-document-adapter.js';
|
|
11
|
+
// Filesystem client (re-export for convenience)
|
|
12
|
+
export { readFile, writeFile, listFiles, parseFrontmatter, serializeFrontmatter, FolderFsError, isFolderFsError, } from './folder-fs.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/external-sync/providers/folder/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,mBAAmB;AACnB,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,mBAAmB;AACnB,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,OAAO,GACR,MAAM,8BAA8B,CAAC;AAEtC,gDAAgD;AAChD,OAAO,EACL,QAAQ,EACR,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAC"}
|