notion-doc-sync 1.0.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 +203 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +80 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/analyze.d.ts +6 -0
- package/dist/commands/analyze.js +58 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/fetch.d.ts +2 -0
- package/dist/commands/fetch.js +26 -0
- package/dist/commands/fetch.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +21 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/stamp.d.ts +2 -0
- package/dist/commands/stamp.js +57 -0
- package/dist/commands/stamp.js.map +1 -0
- package/dist/commands/sync.d.ts +6 -0
- package/dist/commands/sync.js +125 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/lib/config.d.ts +32 -0
- package/dist/lib/config.js +85 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/doc-mapper.d.ts +111 -0
- package/dist/lib/doc-mapper.js +390 -0
- package/dist/lib/doc-mapper.js.map +1 -0
- package/dist/lib/git-analyzer.d.ts +14 -0
- package/dist/lib/git-analyzer.js +132 -0
- package/dist/lib/git-analyzer.js.map +1 -0
- package/dist/lib/local-docs-reader.d.ts +24 -0
- package/dist/lib/local-docs-reader.js +163 -0
- package/dist/lib/local-docs-reader.js.map +1 -0
- package/dist/lib/md-to-notion-converter.d.ts +5 -0
- package/dist/lib/md-to-notion-converter.js +14 -0
- package/dist/lib/md-to-notion-converter.js.map +1 -0
- package/dist/lib/notion-client.d.ts +29 -0
- package/dist/lib/notion-client.js +183 -0
- package/dist/lib/notion-client.js.map +1 -0
- package/dist/lib/notion-md-converter.d.ts +7 -0
- package/dist/lib/notion-md-converter.js +17 -0
- package/dist/lib/notion-md-converter.js.map +1 -0
- package/dist/lib/timestamp-utils.d.ts +7 -0
- package/dist/lib/timestamp-utils.js +47 -0
- package/dist/lib/timestamp-utils.js.map +1 -0
- package/dist/types/doc-sync.d.ts +103 -0
- package/dist/types/doc-sync.js +6 -0
- package/dist/types/doc-sync.js.map +1 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# notion-doc-sync
|
|
2
|
+
|
|
3
|
+
A CLI tool that keeps Notion documentation aligned with code changes. It fetches Notion pages as local Markdown, detects git changes, maps them to relevant docs, and supports bidirectional sync between local files and Notion.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js >= 18.0.0 (22.x recommended — use `nvm use` to auto-switch)
|
|
8
|
+
- npm
|
|
9
|
+
- A [Notion integration](https://developers.notion.com/) with access to your documentation pages
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Install globally from npm
|
|
15
|
+
npm install -g notion-doc-sync
|
|
16
|
+
|
|
17
|
+
# Initialise config in your project
|
|
18
|
+
notion-doc-sync init
|
|
19
|
+
|
|
20
|
+
# Edit .notion-doc-sync.json with your Notion API key and database ID
|
|
21
|
+
|
|
22
|
+
# Fetch docs from Notion
|
|
23
|
+
notion-doc-sync fetch
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## CLI Commands
|
|
27
|
+
|
|
28
|
+
### `notion-doc-sync init`
|
|
29
|
+
|
|
30
|
+
Creates a `.notion-doc-sync.json` config file in the current directory with default settings. Edit this file to add your Notion API key and database ID.
|
|
31
|
+
|
|
32
|
+
### `notion-doc-sync fetch`
|
|
33
|
+
|
|
34
|
+
Fetches documentation pages from Notion and saves/updates them as local Markdown files in the configured docs directory (default: `./notionDocs`). Pages are matched by the page IDs stored in each local file's frontmatter.
|
|
35
|
+
|
|
36
|
+
### `notion-doc-sync analyze`
|
|
37
|
+
|
|
38
|
+
Analyses git changes between two branches and maps them to documentation files using heuristic matching with confidence scores.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
notion-doc-sync analyze # compare main..HEAD
|
|
42
|
+
notion-doc-sync analyze --base-branch develop # custom base branch
|
|
43
|
+
notion-doc-sync analyze --target-branch feature/foo # custom target branch
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### `notion-doc-sync sync`
|
|
47
|
+
|
|
48
|
+
Bidirectional sync between local docs and Notion. Compares timestamps to determine whether each file should be pulled from Notion or pushed to Notion.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
notion-doc-sync sync # execute sync
|
|
52
|
+
notion-doc-sync sync --dry-run # preview actions without making changes
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### `notion-doc-sync stamp`
|
|
56
|
+
|
|
57
|
+
Updates the `lastUpdated` timestamp in the frontmatter of any locally modified Markdown files (detected via `git status`). Useful before pushing changes to Notion.
|
|
58
|
+
|
|
59
|
+
## Configuration
|
|
60
|
+
|
|
61
|
+
Configuration is read from `.notion-doc-sync.json` in the project root. Run `notion-doc-sync init` to generate one.
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"notionApiKey": "",
|
|
66
|
+
"notionDatabaseId": "",
|
|
67
|
+
"sourceDir": "./src",
|
|
68
|
+
"docsDir": "./notionDocs",
|
|
69
|
+
"excludePatterns": [
|
|
70
|
+
"node_modules/**",
|
|
71
|
+
"dist/**",
|
|
72
|
+
"**/*.test.ts",
|
|
73
|
+
"**/*.spec.ts",
|
|
74
|
+
"**/__tests__/**",
|
|
75
|
+
".git/**"
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
| Field | Description | Default |
|
|
81
|
+
| ------------------ | -------------------------------------- | -------------- |
|
|
82
|
+
| `notionApiKey` | Notion integration API key | — |
|
|
83
|
+
| `notionDatabaseId` | Target Notion database ID | — |
|
|
84
|
+
| `sourceDir` | Source code directory to analyse | `./src` |
|
|
85
|
+
| `docsDir` | Local docs directory | `./notionDocs` |
|
|
86
|
+
| `excludePatterns` | Glob patterns to exclude from analysis | See above |
|
|
87
|
+
|
|
88
|
+
### Setting up Notion
|
|
89
|
+
|
|
90
|
+
1. Go to [Notion Developers](https://developers.notion.com/) and create a new integration.
|
|
91
|
+
2. Copy the integration token into `notionApiKey` in your config file.
|
|
92
|
+
3. Share your documentation database/pages with the integration.
|
|
93
|
+
4. Copy the database ID into `notionDatabaseId`.
|
|
94
|
+
|
|
95
|
+
## Repository Structure
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
src/
|
|
99
|
+
├── cli.ts # CLI entry point (commander)
|
|
100
|
+
├── commands/
|
|
101
|
+
│ ├── fetch.ts # fetch command
|
|
102
|
+
│ ├── analyze.ts # analyze command
|
|
103
|
+
│ ├── init.ts # init command
|
|
104
|
+
│ ├── sync.ts # sync command
|
|
105
|
+
│ └── stamp.ts # stamp command
|
|
106
|
+
├── lib/
|
|
107
|
+
│ ├── config.ts # Config loading and validation
|
|
108
|
+
│ ├── notion-client.ts # Notion API wrapper
|
|
109
|
+
│ ├── local-docs-reader.ts # Local Markdown file reader/writer
|
|
110
|
+
│ ├── doc-mapper.ts # Doc-to-code mapping with confidence scores
|
|
111
|
+
│ ├── git-analyzer.ts # Git diff extraction between branches
|
|
112
|
+
│ ├── md-to-notion-converter.ts # Markdown to Notion block converter
|
|
113
|
+
│ ├── notion-md-converter.ts # Notion to Markdown converter
|
|
114
|
+
│ └── timestamp-utils.ts # Timestamp comparison utilities
|
|
115
|
+
├── types/
|
|
116
|
+
│ └── doc-sync.ts # TypeScript interfaces and types
|
|
117
|
+
└── __tests__/ # Tests (mirrors src structure)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Local Development
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Clone the repo
|
|
124
|
+
git clone <repo-url>
|
|
125
|
+
cd NotionDocFetcher
|
|
126
|
+
|
|
127
|
+
# Use the correct Node version
|
|
128
|
+
nvm use
|
|
129
|
+
|
|
130
|
+
# Install dependencies
|
|
131
|
+
npm install
|
|
132
|
+
|
|
133
|
+
# Run in development mode (via ts-node)
|
|
134
|
+
npm run dev -- fetch
|
|
135
|
+
npm run dev -- analyze --base-branch main
|
|
136
|
+
npm run dev -- sync --dry-run
|
|
137
|
+
|
|
138
|
+
# Build
|
|
139
|
+
npm run build
|
|
140
|
+
|
|
141
|
+
# Run the built CLI
|
|
142
|
+
node dist/cli.js fetch
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Available Scripts
|
|
146
|
+
|
|
147
|
+
| Script | Description |
|
|
148
|
+
| ----------------------- | ------------------------------------------ |
|
|
149
|
+
| `npm run build` | Compile TypeScript to `dist/` |
|
|
150
|
+
| `npm run dev` | Run via ts-node (pass CLI args after `--`) |
|
|
151
|
+
| `npm test` | Run all tests once |
|
|
152
|
+
| `npm run test:watch` | Run tests in watch mode |
|
|
153
|
+
| `npm run test:coverage` | Coverage report (90% threshold enforced) |
|
|
154
|
+
| `npm run lint` | ESLint |
|
|
155
|
+
| `npm run lint:fix` | Auto-fix lint issues |
|
|
156
|
+
| `npm run format` | Prettier formatting |
|
|
157
|
+
| `npm run type-check` | TypeScript type check without emit |
|
|
158
|
+
| `npm run clean` | Remove `dist/` |
|
|
159
|
+
|
|
160
|
+
### Running a Single Test File
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npx vitest run src/__tests__/doc-mapper.test.ts
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Deployment
|
|
167
|
+
|
|
168
|
+
### Publishing to npm
|
|
169
|
+
|
|
170
|
+
The package is configured for npm publishing with the binary name `notion-doc-sync`.
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# Build, test, and publish (prepublishOnly runs automatically)
|
|
174
|
+
npm publish
|
|
175
|
+
|
|
176
|
+
# Or step by step:
|
|
177
|
+
npm run clean
|
|
178
|
+
npm run build
|
|
179
|
+
npm test
|
|
180
|
+
npm publish
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The published package includes only the compiled JavaScript (`dist/`), type declarations, README, and LICENSE.
|
|
184
|
+
|
|
185
|
+
### Installing from npm
|
|
186
|
+
|
|
187
|
+
Once published, users install it globally:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npm install -g notion-doc-sync
|
|
191
|
+
notion-doc-sync --help
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Or use it as a project-local dev dependency:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
npm install --save-dev notion-doc-sync
|
|
198
|
+
npx notion-doc-sync fetch
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
MIT
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
/* eslint-disable no-console */
|
|
5
|
+
const commander_1 = require("commander");
|
|
6
|
+
const fetch_1 = require("./commands/fetch");
|
|
7
|
+
const analyze_1 = require("./commands/analyze");
|
|
8
|
+
const init_1 = require("./commands/init");
|
|
9
|
+
const sync_1 = require("./commands/sync");
|
|
10
|
+
const stamp_1 = require("./commands/stamp");
|
|
11
|
+
const program = new commander_1.Command();
|
|
12
|
+
program
|
|
13
|
+
.name('notion-doc-sync')
|
|
14
|
+
.description('CLI tool to keep Notion documentation aligned with code changes')
|
|
15
|
+
.version('1.0.0');
|
|
16
|
+
program
|
|
17
|
+
.command('fetch')
|
|
18
|
+
.description('Fetch documentation from Notion and save locally')
|
|
19
|
+
.action(async () => {
|
|
20
|
+
try {
|
|
21
|
+
await (0, fetch_1.fetchCommand)();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
program
|
|
29
|
+
.command('analyze')
|
|
30
|
+
.description('Analyze git changes and map to documentation files')
|
|
31
|
+
.option('--base-branch <branch>', 'Base branch for comparison', 'main')
|
|
32
|
+
.option('--target-branch <branch>', 'Target branch for comparison', 'HEAD')
|
|
33
|
+
.action(async (options) => {
|
|
34
|
+
try {
|
|
35
|
+
await (0, analyze_1.analyzeCommand)(options);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
program
|
|
43
|
+
.command('init')
|
|
44
|
+
.description('Create a .notion-doc-sync.json config file')
|
|
45
|
+
.action(() => {
|
|
46
|
+
try {
|
|
47
|
+
(0, init_1.initCommand)();
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
program
|
|
55
|
+
.command('sync')
|
|
56
|
+
.description('Bidirectional sync between local docs and Notion')
|
|
57
|
+
.option('--dry-run', 'Preview sync actions without making changes')
|
|
58
|
+
.action(async (options) => {
|
|
59
|
+
try {
|
|
60
|
+
await (0, sync_1.syncCommand)(options);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
program
|
|
68
|
+
.command('stamp')
|
|
69
|
+
.description('Update timestamps on locally modified documentation files')
|
|
70
|
+
.action(async () => {
|
|
71
|
+
try {
|
|
72
|
+
await (0, stamp_1.stampCommand)();
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
program.parse();
|
|
80
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.analyzeCommand = analyzeCommand;
|
|
4
|
+
/* eslint-disable no-console */
|
|
5
|
+
const config_1 = require("../lib/config");
|
|
6
|
+
const git_analyzer_1 = require("../lib/git-analyzer");
|
|
7
|
+
const doc_mapper_1 = require("../lib/doc-mapper");
|
|
8
|
+
const local_docs_reader_1 = require("../lib/local-docs-reader");
|
|
9
|
+
const promises_1 = require("fs/promises");
|
|
10
|
+
async function analyzeCommand(options) {
|
|
11
|
+
const config = (0, config_1.resolveConfig)();
|
|
12
|
+
const baseBranch = options.baseBranch ?? 'main';
|
|
13
|
+
const targetBranch = options.targetBranch ?? 'HEAD';
|
|
14
|
+
console.log(`Analyzing changes between ${baseBranch} and ${targetBranch}...`);
|
|
15
|
+
const gitAnalyzer = new git_analyzer_1.GitAnalyzer();
|
|
16
|
+
const changes = gitAnalyzer.getCodeChanges(baseBranch, targetBranch);
|
|
17
|
+
if (changes.length === 0) {
|
|
18
|
+
console.log('No code changes detected between branches.');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
console.log(`Found ${changes.length} changed code file(s)`);
|
|
22
|
+
const localDocsReader = new local_docs_reader_1.LocalDocsReader(config.analysis.docsDir);
|
|
23
|
+
const localDocs = await localDocsReader.readLocalDocs();
|
|
24
|
+
const documentationFiles = [];
|
|
25
|
+
for (const doc of localDocs) {
|
|
26
|
+
const content = await (0, promises_1.readFile)(doc.filePath, 'utf-8');
|
|
27
|
+
documentationFiles.push({
|
|
28
|
+
filePath: doc.filePath,
|
|
29
|
+
content,
|
|
30
|
+
linkedCodeFiles: [],
|
|
31
|
+
mappingConfidence: 0,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const changedFilePaths = changes.map((c) => c.filePath);
|
|
35
|
+
const docMapper = new doc_mapper_1.DocMapper();
|
|
36
|
+
const enhanced = docMapper.enhanceDocumentationFiles(documentationFiles, changedFilePaths);
|
|
37
|
+
const affected = enhanced.filter((doc) => doc.linkedCodeFiles.length > 0);
|
|
38
|
+
if (affected.length === 0) {
|
|
39
|
+
console.log('No documentation files are linked to the changed code files.');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
console.log('\nDocumentation files potentially affected by code changes:\n');
|
|
43
|
+
console.log(padRight('Document', 40) + padRight('Linked Code Files', 45) + padRight('Confidence', 12));
|
|
44
|
+
console.log('-'.repeat(97));
|
|
45
|
+
for (const doc of affected) {
|
|
46
|
+
const docName = doc.filePath;
|
|
47
|
+
const linkedFiles = doc.linkedCodeFiles.join(', ');
|
|
48
|
+
const confidence = (doc.mappingConfidence * 100).toFixed(0) + '%';
|
|
49
|
+
console.log(padRight(docName, 40) + padRight(linkedFiles, 45) + padRight(confidence, 12));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function padRight(str, length) {
|
|
53
|
+
if (str.length >= length) {
|
|
54
|
+
return str.substring(0, length - 3) + '...';
|
|
55
|
+
}
|
|
56
|
+
return str + ' '.repeat(length - str.length);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":";;AAaA,wCAsDC;AAnED,+BAA+B;AAC/B,0CAA8C;AAC9C,sDAAkD;AAClD,kDAA8C;AAC9C,gEAA2D;AAE3D,0CAAuC;AAOhC,KAAK,UAAU,cAAc,CAAC,OAAuB;IAC1D,MAAM,MAAM,GAAG,IAAA,sBAAa,GAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC;IAChD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,MAAM,CAAC;IAEpD,OAAO,CAAC,GAAG,CAAC,6BAA6B,UAAU,QAAQ,YAAY,KAAK,CAAC,CAAC;IAE9E,MAAM,WAAW,GAAG,IAAI,0BAAW,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAErE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAC1D,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,SAAS,OAAO,CAAC,MAAM,uBAAuB,CAAC,CAAC;IAE5D,MAAM,eAAe,GAAG,IAAI,mCAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACrE,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,aAAa,EAAE,CAAC;IAExD,MAAM,kBAAkB,GAAwB,EAAE,CAAC;IACnD,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACtD,kBAAkB,CAAC,IAAI,CAAC;YACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,OAAO;YACP,eAAe,EAAE,EAAE;YACnB,iBAAiB,EAAE,CAAC;SACrB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,IAAI,sBAAS,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAG,SAAS,CAAC,yBAAyB,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAC;IAE3F,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE1E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;QAC5E,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CACT,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC,mBAAmB,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC,YAAY,EAAE,EAAE,CAAC,CAC1F,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC7B,MAAM,WAAW,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,iBAAiB,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW,EAAE,MAAc;IAC3C,IAAI,GAAG,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;IAC9C,CAAC;IACD,OAAO,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchCommand = fetchCommand;
|
|
4
|
+
/* eslint-disable no-console */
|
|
5
|
+
const config_1 = require("../lib/config");
|
|
6
|
+
const notion_client_1 = require("../lib/notion-client");
|
|
7
|
+
const local_docs_reader_1 = require("../lib/local-docs-reader");
|
|
8
|
+
async function fetchCommand() {
|
|
9
|
+
console.log('Starting documentation synchronization...');
|
|
10
|
+
const config = (0, config_1.resolveConfig)();
|
|
11
|
+
const notionClient = new notion_client_1.NotionClient(config.notion.apiKey);
|
|
12
|
+
const localDocsReader = new local_docs_reader_1.LocalDocsReader(config.analysis.docsDir);
|
|
13
|
+
console.log('Reading local documentation files...');
|
|
14
|
+
const pageIds = await localDocsReader.getPageIds();
|
|
15
|
+
if (pageIds.length === 0) {
|
|
16
|
+
console.log('No local docs found with page IDs. Nothing to fetch.');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
console.log('Fetching Notion documentation...');
|
|
20
|
+
const docs = await notionClient.fetchPagesByIds(pageIds);
|
|
21
|
+
console.log(`Found ${docs.length} documentation pages`);
|
|
22
|
+
console.log('Updating local documentation files...');
|
|
23
|
+
await localDocsReader.updateLocalDocs(docs);
|
|
24
|
+
console.log('Documentation sync completed successfully');
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/commands/fetch.ts"],"names":[],"mappings":";;AAKA,oCAwBC;AA7BD,+BAA+B;AAC/B,0CAA8C;AAC9C,wDAAoD;AACpD,gEAA2D;AAEpD,KAAK,UAAU,YAAY;IAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAEzD,MAAM,MAAM,GAAG,IAAA,sBAAa,GAAE,CAAC;IAE/B,MAAM,YAAY,GAAG,IAAI,4BAAY,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,eAAe,GAAG,IAAI,mCAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAErE,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,UAAU,EAAE,CAAC;IAEnD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;QACpE,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,MAAM,sBAAsB,CAAC,CAAC;IAExD,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IACrD,MAAM,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IAE5C,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initCommand = initCommand;
|
|
4
|
+
/* eslint-disable no-console */
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const config_1 = require("../lib/config");
|
|
8
|
+
const CONFIG_FILENAME = '.notion-doc-sync.json';
|
|
9
|
+
function initCommand() {
|
|
10
|
+
const configPath = (0, path_1.join)(process.cwd(), CONFIG_FILENAME);
|
|
11
|
+
if ((0, fs_1.existsSync)(configPath)) {
|
|
12
|
+
console.log(`Config file already exists: ${configPath}`);
|
|
13
|
+
console.log('Remove it first if you want to reinitialize.');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const defaultConfig = (0, config_1.getDefaultConfig)();
|
|
17
|
+
(0, fs_1.writeFileSync)(configPath, JSON.stringify(defaultConfig, null, 2) + '\n', 'utf-8');
|
|
18
|
+
console.log(`Created config file: ${configPath}`);
|
|
19
|
+
console.log('Edit the file to add your Notion API key and database ID.');
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":";;AAOA,kCAcC;AArBD,+BAA+B;AAC/B,2BAA+C;AAC/C,+BAA4B;AAC5B,0CAAiD;AAEjD,MAAM,eAAe,GAAG,uBAAuB,CAAC;AAEhD,SAAgB,WAAW;IACzB,MAAM,UAAU,GAAG,IAAA,WAAI,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;IAExD,IAAI,IAAA,eAAU,EAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC5D,OAAO;IACT,CAAC;IAED,MAAM,aAAa,GAAG,IAAA,yBAAgB,GAAE,CAAC;IACzC,IAAA,kBAAa,EAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAElF,OAAO,CAAC,GAAG,CAAC,wBAAwB,UAAU,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stampCommand = stampCommand;
|
|
4
|
+
/* eslint-disable no-console */
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const promises_1 = require("fs/promises");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const config_1 = require("../lib/config");
|
|
9
|
+
const timestamp_utils_1 = require("../lib/timestamp-utils");
|
|
10
|
+
async function stampCommand() {
|
|
11
|
+
const config = (0, config_1.resolveConfig)();
|
|
12
|
+
const docsDir = config.analysis.docsDir;
|
|
13
|
+
console.log(`Checking for modified docs in: ${docsDir}`);
|
|
14
|
+
const modifiedFiles = getModifiedMarkdownFiles(docsDir);
|
|
15
|
+
if (modifiedFiles.length === 0) {
|
|
16
|
+
console.log('No modified markdown files found.');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const now = new Date();
|
|
20
|
+
let stamped = 0;
|
|
21
|
+
for (const filePath of modifiedFiles) {
|
|
22
|
+
try {
|
|
23
|
+
const fullPath = (0, path_1.join)(process.cwd(), filePath);
|
|
24
|
+
const content = await (0, promises_1.readFile)(fullPath, 'utf-8');
|
|
25
|
+
const updated = (0, timestamp_utils_1.replaceTimestampInContent)(content, now);
|
|
26
|
+
if (updated !== content) {
|
|
27
|
+
await (0, promises_1.writeFile)(fullPath, updated, 'utf-8');
|
|
28
|
+
console.log(` Stamped: ${filePath}`);
|
|
29
|
+
stamped++;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.log(` Skipped (no timestamp line): ${filePath}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.error(` Failed to stamp ${filePath}:`, error);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
console.log(`\nStamped ${stamped} file(s) with timestamp: ${now.toISOString()}`);
|
|
40
|
+
}
|
|
41
|
+
function getModifiedMarkdownFiles(docsDir) {
|
|
42
|
+
try {
|
|
43
|
+
const output = (0, child_process_1.execSync)(`git status --porcelain -- ${docsDir}`, {
|
|
44
|
+
encoding: 'utf-8',
|
|
45
|
+
});
|
|
46
|
+
return output
|
|
47
|
+
.split('\n')
|
|
48
|
+
.filter((line) => line.trim() !== '')
|
|
49
|
+
.map((line) => line.slice(3).trim())
|
|
50
|
+
.filter((file) => file.endsWith('.md'));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
console.error('Failed to run git status. Are you in a git repository?');
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=stamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stamp.js","sourceRoot":"","sources":["../../src/commands/stamp.ts"],"names":[],"mappings":";;AAOA,oCAmCC;AA1CD,+BAA+B;AAC/B,iDAAyC;AACzC,0CAAkD;AAClD,+BAA4B;AAC5B,0CAA8C;AAC9C,4DAAmE;AAE5D,KAAK,UAAU,YAAY;IAChC,MAAM,MAAM,GAAG,IAAA,sBAAa,GAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,kCAAkC,OAAO,EAAE,CAAC,CAAC;IAEzD,MAAM,aAAa,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAExD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,QAAQ,IAAI,aAAa,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;YAC/C,MAAM,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,OAAO,GAAG,IAAA,2CAAyB,EAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YAExD,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;gBACxB,MAAM,IAAA,oBAAS,EAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,cAAc,QAAQ,EAAE,CAAC,CAAC;gBACtC,OAAO,EAAE,CAAC;YACZ,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,kCAAkC,QAAQ,EAAE,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,qBAAqB,QAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,aAAa,OAAO,4BAA4B,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,wBAAwB,CAAC,OAAe;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,wBAAQ,EAAC,6BAA6B,OAAO,EAAE,EAAE;YAC9D,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QAEH,OAAO,MAAM;aACV,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;aACpC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACnC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;QACxE,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.syncCommand = syncCommand;
|
|
4
|
+
/* eslint-disable no-console */
|
|
5
|
+
const config_1 = require("../lib/config");
|
|
6
|
+
const notion_client_1 = require("../lib/notion-client");
|
|
7
|
+
const md_to_notion_converter_1 = require("../lib/md-to-notion-converter");
|
|
8
|
+
const local_docs_reader_1 = require("../lib/local-docs-reader");
|
|
9
|
+
const timestamp_utils_1 = require("../lib/timestamp-utils");
|
|
10
|
+
async function syncCommand(options = {}) {
|
|
11
|
+
const config = (0, config_1.resolveConfig)();
|
|
12
|
+
(0, config_1.validateConfig)(config, ['notionApiKey']);
|
|
13
|
+
const notionClient = new notion_client_1.NotionClient(config.notion.apiKey);
|
|
14
|
+
const mdToNotion = new md_to_notion_converter_1.MdToNotionConverter();
|
|
15
|
+
const localDocsReader = new local_docs_reader_1.LocalDocsReader(config.analysis.docsDir);
|
|
16
|
+
console.log('Reading local documentation files...');
|
|
17
|
+
const localDocs = await localDocsReader.readLocalDocs();
|
|
18
|
+
if (localDocs.length === 0) {
|
|
19
|
+
console.log('No local docs found with page IDs. Nothing to sync.');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
console.log('Determining sync actions...');
|
|
23
|
+
const actions = [];
|
|
24
|
+
for (const localDoc of localDocs) {
|
|
25
|
+
try {
|
|
26
|
+
const metadata = await localDocsReader.readFullDoc(localDoc);
|
|
27
|
+
const notionTimestamp = await notionClient.fetchPageLastEdited(localDoc.pageId);
|
|
28
|
+
const direction = (0, timestamp_utils_1.compareSyncTimestamps)(metadata.lastUpdated, notionTimestamp);
|
|
29
|
+
actions.push({
|
|
30
|
+
pageId: localDoc.pageId,
|
|
31
|
+
filePath: localDoc.filePath,
|
|
32
|
+
fileName: localDoc.fileName,
|
|
33
|
+
direction,
|
|
34
|
+
localTimestamp: metadata.lastUpdated,
|
|
35
|
+
notionTimestamp,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.error(` Failed to check ${localDoc.fileName}:`, error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
printActionSummary(actions);
|
|
43
|
+
if (options.dryRun === true) {
|
|
44
|
+
console.log('\n--dry-run: No changes made.');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const results = await executeActions(actions, notionClient, mdToNotion, localDocsReader);
|
|
48
|
+
printResults(results);
|
|
49
|
+
}
|
|
50
|
+
async function executeActions(actions, notionClient, mdToNotion, localDocsReader) {
|
|
51
|
+
const results = [];
|
|
52
|
+
for (const action of actions) {
|
|
53
|
+
if (action.direction === 'none') {
|
|
54
|
+
results.push({
|
|
55
|
+
pageId: action.pageId,
|
|
56
|
+
fileName: action.fileName,
|
|
57
|
+
direction: 'none',
|
|
58
|
+
success: true,
|
|
59
|
+
});
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
if (action.direction === 'pull') {
|
|
64
|
+
const docs = await notionClient.fetchPagesByIds([action.pageId]);
|
|
65
|
+
if (docs.length > 0) {
|
|
66
|
+
await localDocsReader.updateLocalDocs(docs);
|
|
67
|
+
}
|
|
68
|
+
results.push({
|
|
69
|
+
pageId: action.pageId,
|
|
70
|
+
fileName: action.fileName,
|
|
71
|
+
direction: 'pull',
|
|
72
|
+
success: true,
|
|
73
|
+
synchronizedTimestamp: action.notionTimestamp,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const metadata = await localDocsReader.readFullDoc({
|
|
78
|
+
filePath: action.filePath,
|
|
79
|
+
fileName: action.fileName,
|
|
80
|
+
pageId: action.pageId,
|
|
81
|
+
});
|
|
82
|
+
const blocks = mdToNotion.convertToBlocks(metadata.bodyContent);
|
|
83
|
+
await notionClient.replacePageContent(action.pageId, blocks);
|
|
84
|
+
const newNotionTimestamp = await notionClient.fetchPageLastEdited(action.pageId);
|
|
85
|
+
await localDocsReader.updateTimestampOnly(action.filePath, newNotionTimestamp);
|
|
86
|
+
results.push({
|
|
87
|
+
pageId: action.pageId,
|
|
88
|
+
fileName: action.fileName,
|
|
89
|
+
direction: 'push',
|
|
90
|
+
success: true,
|
|
91
|
+
synchronizedTimestamp: newNotionTimestamp,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
results.push({
|
|
97
|
+
pageId: action.pageId,
|
|
98
|
+
fileName: action.fileName,
|
|
99
|
+
direction: action.direction,
|
|
100
|
+
success: false,
|
|
101
|
+
error: error instanceof Error ? error.message : String(error),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return results;
|
|
106
|
+
}
|
|
107
|
+
function printActionSummary(actions) {
|
|
108
|
+
const pulls = actions.filter((a) => a.direction === 'pull');
|
|
109
|
+
const pushes = actions.filter((a) => a.direction === 'push');
|
|
110
|
+
const skips = actions.filter((a) => a.direction === 'none');
|
|
111
|
+
console.log(`\nSync plan: ${pulls.length} pull, ${pushes.length} push, ${skips.length} skip`);
|
|
112
|
+
for (const action of actions) {
|
|
113
|
+
const arrow = action.direction === 'pull' ? '<--' : action.direction === 'push' ? '-->' : '===';
|
|
114
|
+
console.log(` ${arrow} ${action.fileName} (${action.direction})`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function printResults(results) {
|
|
118
|
+
const successes = results.filter((r) => r.success);
|
|
119
|
+
const failures = results.filter((r) => !r.success);
|
|
120
|
+
console.log(`\nSync complete: ${successes.length} succeeded, ${failures.length} failed`);
|
|
121
|
+
for (const failure of failures) {
|
|
122
|
+
console.error(` FAILED ${failure.fileName}: ${failure.error ?? 'unknown error'}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
|