@nathanvale/chatline 0.0.1
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/CHANGELOG.md +1 -0
- package/LICENSE +21 -0
- package/README.md +1535 -0
- package/dist/bin/index.js +5121 -0
- package/dist/cli/commands/clean.d.ts +17 -0
- package/dist/cli/commands/clean.d.ts.map +1 -0
- package/dist/cli/commands/clean.js +142 -0
- package/dist/cli/commands/clean.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +17 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +202 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/enrich-ai.d.ts +17 -0
- package/dist/cli/commands/enrich-ai.d.ts.map +1 -0
- package/dist/cli/commands/enrich-ai.js +371 -0
- package/dist/cli/commands/enrich-ai.js.map +1 -0
- package/dist/cli/commands/index.d.ts +16 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +16 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/ingest-csv.d.ts +17 -0
- package/dist/cli/commands/ingest-csv.d.ts.map +1 -0
- package/dist/cli/commands/ingest-csv.js +138 -0
- package/dist/cli/commands/ingest-csv.js.map +1 -0
- package/dist/cli/commands/ingest-db.d.ts +17 -0
- package/dist/cli/commands/ingest-db.d.ts.map +1 -0
- package/dist/cli/commands/ingest-db.js +159 -0
- package/dist/cli/commands/ingest-db.js.map +1 -0
- package/dist/cli/commands/init.d.ts +17 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +110 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/normalize-link.d.ts +16 -0
- package/dist/cli/commands/normalize-link.d.ts.map +1 -0
- package/dist/cli/commands/normalize-link.js +144 -0
- package/dist/cli/commands/normalize-link.js.map +1 -0
- package/dist/cli/commands/render-markdown.d.ts +17 -0
- package/dist/cli/commands/render-markdown.d.ts.map +1 -0
- package/dist/cli/commands/render-markdown.js +218 -0
- package/dist/cli/commands/render-markdown.js.map +1 -0
- package/dist/cli/commands/stats.d.ts +17 -0
- package/dist/cli/commands/stats.d.ts.map +1 -0
- package/dist/cli/commands/stats.js +175 -0
- package/dist/cli/commands/stats.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +17 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +152 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +121 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/types.d.ts +93 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +7 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/utils.d.ts +29 -0
- package/dist/cli/utils.d.ts.map +1 -0
- package/dist/cli/utils.js +53 -0
- package/dist/cli/utils.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1805 -0
- package/dist/config/generator.d.ts +90 -0
- package/dist/config/generator.d.ts.map +1 -0
- package/dist/config/generator.js +320 -0
- package/dist/config/generator.js.map +1 -0
- package/dist/config/loader.d.ts +107 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +251 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +107 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +169 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/enrich/audio-transcription.d.ts +77 -0
- package/dist/enrich/audio-transcription.d.ts.map +1 -0
- package/dist/enrich/audio-transcription.js +370 -0
- package/dist/enrich/audio-transcription.js.map +1 -0
- package/dist/enrich/checkpoint.d.ts +137 -0
- package/dist/enrich/checkpoint.d.ts.map +1 -0
- package/dist/enrich/checkpoint.js +205 -0
- package/dist/enrich/checkpoint.js.map +1 -0
- package/dist/enrich/idempotency.d.ts +90 -0
- package/dist/enrich/idempotency.d.ts.map +1 -0
- package/dist/enrich/idempotency.js +188 -0
- package/dist/enrich/idempotency.js.map +1 -0
- package/dist/enrich/image-analysis.d.ts +62 -0
- package/dist/enrich/image-analysis.d.ts.map +1 -0
- package/dist/enrich/image-analysis.js +264 -0
- package/dist/enrich/image-analysis.js.map +1 -0
- package/dist/enrich/index.d.ts +60 -0
- package/dist/enrich/index.d.ts.map +1 -0
- package/dist/enrich/index.js +74 -0
- package/dist/enrich/index.js.map +1 -0
- package/dist/enrich/link-enrichment.d.ts +37 -0
- package/dist/enrich/link-enrichment.d.ts.map +1 -0
- package/dist/enrich/link-enrichment.js +202 -0
- package/dist/enrich/link-enrichment.js.map +1 -0
- package/dist/enrich/pdf-video-handling.d.ts +49 -0
- package/dist/enrich/pdf-video-handling.d.ts.map +1 -0
- package/dist/enrich/pdf-video-handling.js +325 -0
- package/dist/enrich/pdf-video-handling.js.map +1 -0
- package/dist/enrich/progress-tracker.d.ts +120 -0
- package/dist/enrich/progress-tracker.d.ts.map +1 -0
- package/dist/enrich/progress-tracker.js +220 -0
- package/dist/enrich/progress-tracker.js.map +1 -0
- package/dist/enrich/providers/firecrawl.d.ts +18 -0
- package/dist/enrich/providers/firecrawl.d.ts.map +1 -0
- package/dist/enrich/providers/firecrawl.js +48 -0
- package/dist/enrich/providers/firecrawl.js.map +1 -0
- package/dist/enrich/providers/generic.d.ts +16 -0
- package/dist/enrich/providers/generic.d.ts.map +1 -0
- package/dist/enrich/providers/generic.js +36 -0
- package/dist/enrich/providers/generic.js.map +1 -0
- package/dist/enrich/providers/index.d.ts +14 -0
- package/dist/enrich/providers/index.d.ts.map +1 -0
- package/dist/enrich/providers/index.js +13 -0
- package/dist/enrich/providers/index.js.map +1 -0
- package/dist/enrich/providers/instagram.d.ts +16 -0
- package/dist/enrich/providers/instagram.d.ts.map +1 -0
- package/dist/enrich/providers/instagram.js +43 -0
- package/dist/enrich/providers/instagram.js.map +1 -0
- package/dist/enrich/providers/spotify.d.ts +16 -0
- package/dist/enrich/providers/spotify.d.ts.map +1 -0
- package/dist/enrich/providers/spotify.js +45 -0
- package/dist/enrich/providers/spotify.js.map +1 -0
- package/dist/enrich/providers/twitter.d.ts +16 -0
- package/dist/enrich/providers/twitter.d.ts.map +1 -0
- package/dist/enrich/providers/twitter.js +43 -0
- package/dist/enrich/providers/twitter.js.map +1 -0
- package/dist/enrich/providers/types.d.ts +47 -0
- package/dist/enrich/providers/types.d.ts.map +1 -0
- package/dist/enrich/providers/types.js +15 -0
- package/dist/enrich/providers/types.js.map +1 -0
- package/dist/enrich/providers/youtube.d.ts +16 -0
- package/dist/enrich/providers/youtube.d.ts.map +1 -0
- package/dist/enrich/providers/youtube.js +43 -0
- package/dist/enrich/providers/youtube.js.map +1 -0
- package/dist/enrich/rate-limiting.d.ts +118 -0
- package/dist/enrich/rate-limiting.d.ts.map +1 -0
- package/dist/enrich/rate-limiting.js +258 -0
- package/dist/enrich/rate-limiting.js.map +1 -0
- package/dist/index.d.ts +688 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1729 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/dedup-merge.d.ts +82 -0
- package/dist/ingest/dedup-merge.d.ts.map +1 -0
- package/dist/ingest/dedup-merge.js +262 -0
- package/dist/ingest/dedup-merge.js.map +1 -0
- package/dist/ingest/ingest-csv.d.ts +62 -0
- package/dist/ingest/ingest-csv.d.ts.map +1 -0
- package/dist/ingest/ingest-csv.js +300 -0
- package/dist/ingest/ingest-csv.js.map +1 -0
- package/dist/ingest/ingest-db.d.ts +64 -0
- package/dist/ingest/ingest-db.d.ts.map +1 -0
- package/dist/ingest/ingest-db.js +172 -0
- package/dist/ingest/ingest-db.js.map +1 -0
- package/dist/ingest/link-replies-and-tapbacks.d.ts +53 -0
- package/dist/ingest/link-replies-and-tapbacks.d.ts.map +1 -0
- package/dist/ingest/link-replies-and-tapbacks.js +381 -0
- package/dist/ingest/link-replies-and-tapbacks.js.map +1 -0
- package/dist/normalize/date-converters.d.ts +45 -0
- package/dist/normalize/date-converters.d.ts.map +1 -0
- package/dist/normalize/date-converters.js +166 -0
- package/dist/normalize/date-converters.js.map +1 -0
- package/dist/normalize/path-validator.d.ts +65 -0
- package/dist/normalize/path-validator.d.ts.map +1 -0
- package/dist/normalize/path-validator.js +221 -0
- package/dist/normalize/path-validator.js.map +1 -0
- package/dist/normalize/validate-normalized.d.ts +45 -0
- package/dist/normalize/validate-normalized.d.ts.map +1 -0
- package/dist/normalize/validate-normalized.js +144 -0
- package/dist/normalize/validate-normalized.js.map +1 -0
- package/dist/render/embeds-blockquotes.d.ts +84 -0
- package/dist/render/embeds-blockquotes.d.ts.map +1 -0
- package/dist/render/embeds-blockquotes.js +204 -0
- package/dist/render/embeds-blockquotes.js.map +1 -0
- package/dist/render/grouping.d.ts +78 -0
- package/dist/render/grouping.d.ts.map +1 -0
- package/dist/render/grouping.js +134 -0
- package/dist/render/grouping.js.map +1 -0
- package/dist/render/index.d.ts +47 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +245 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/reply-rendering.d.ts +88 -0
- package/dist/render/reply-rendering.d.ts.map +1 -0
- package/dist/render/reply-rendering.js +196 -0
- package/dist/render/reply-rendering.js.map +1 -0
- package/dist/schema/message.d.ts +125 -0
- package/dist/schema/message.d.ts.map +1 -0
- package/dist/schema/message.js +331 -0
- package/dist/schema/message.js.map +1 -0
- package/dist/utils/delta-detection.d.ts +107 -0
- package/dist/utils/delta-detection.d.ts.map +1 -0
- package/dist/utils/delta-detection.js +199 -0
- package/dist/utils/delta-detection.js.map +1 -0
- package/dist/utils/enrichment-merge.d.ts +135 -0
- package/dist/utils/enrichment-merge.d.ts.map +1 -0
- package/dist/utils/enrichment-merge.js +280 -0
- package/dist/utils/enrichment-merge.js.map +1 -0
- package/dist/utils/human.d.ts +15 -0
- package/dist/utils/human.d.ts.map +1 -0
- package/dist/utils/human.js +27 -0
- package/dist/utils/human.js.map +1 -0
- package/dist/utils/incremental-state.d.ts +133 -0
- package/dist/utils/incremental-state.d.ts.map +1 -0
- package/dist/utils/incremental-state.js +237 -0
- package/dist/utils/incremental-state.js.map +1 -0
- package/dist/utils/logger.d.ts +40 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +176 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +165 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config File Generator for iMessage Timeline
|
|
3
|
+
*
|
|
4
|
+
* Implements CONFIG--T03: Add Config Generation Command
|
|
5
|
+
* Generates starter configuration files with documentation comments
|
|
6
|
+
*/
|
|
7
|
+
import type { ConfigFormat } from './schema.js';
|
|
8
|
+
/**
|
|
9
|
+
* CONFIG-T03-AC02: Generate config file content in specified format
|
|
10
|
+
*
|
|
11
|
+
* @param format - Output format ('json' or 'yaml')
|
|
12
|
+
* @returns Formatted config file content as string
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const yamlContent = generateConfigContent('yaml')
|
|
17
|
+
* const jsonContent = generateConfigContent('json')
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateConfigContent(format: ConfigFormat): string;
|
|
21
|
+
/**
|
|
22
|
+
* CONFIG-T03-AC04: Check if config file exists at path
|
|
23
|
+
*
|
|
24
|
+
* @param filePath - Path to check
|
|
25
|
+
* @returns True if file exists and is readable
|
|
26
|
+
*/
|
|
27
|
+
export declare function configFileExists(filePath: string): Promise<boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* CONFIG-T03-AC05: Validate generated config content
|
|
30
|
+
*
|
|
31
|
+
* Parses the generated content and validates against schema
|
|
32
|
+
* to ensure the template produces valid config.
|
|
33
|
+
*
|
|
34
|
+
* @param content - Generated config content
|
|
35
|
+
* @param format - Format of content ('json' | 'yaml')
|
|
36
|
+
* @returns Validation result
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateGeneratedConfig(content: string, format: ConfigFormat): {
|
|
39
|
+
valid: boolean;
|
|
40
|
+
errors?: string[];
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* CONFIG-T03-AC01: Generate config file at specified path
|
|
44
|
+
*
|
|
45
|
+
* Implements the core config generation logic with:
|
|
46
|
+
* - Format selection (YAML/JSON)
|
|
47
|
+
* - Overwrite protection
|
|
48
|
+
* - Content validation
|
|
49
|
+
*
|
|
50
|
+
* @param options - Generation options
|
|
51
|
+
* @param options.filePath - Output file path
|
|
52
|
+
* @param options.format - File format ('json' | 'yaml')
|
|
53
|
+
* @param options.force - Overwrite existing file without prompt
|
|
54
|
+
* @returns Success/failure result
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* // Generate YAML config (default)
|
|
59
|
+
* await generateConfigFile({ filePath: './imessage-config.yaml' })
|
|
60
|
+
*
|
|
61
|
+
* // Generate JSON config
|
|
62
|
+
* await generateConfigFile({
|
|
63
|
+
* filePath: './imessage-config.json',
|
|
64
|
+
* format: 'json'
|
|
65
|
+
* })
|
|
66
|
+
*
|
|
67
|
+
* // Force overwrite
|
|
68
|
+
* await generateConfigFile({
|
|
69
|
+
* filePath: './imessage-config.yaml',
|
|
70
|
+
* force: true
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function generateConfigFile(options: {
|
|
75
|
+
filePath: string;
|
|
76
|
+
format?: ConfigFormat;
|
|
77
|
+
force?: boolean;
|
|
78
|
+
}): Promise<{
|
|
79
|
+
success: boolean;
|
|
80
|
+
message: string;
|
|
81
|
+
filePath: string;
|
|
82
|
+
}>;
|
|
83
|
+
/**
|
|
84
|
+
* Get default config file path for a given format
|
|
85
|
+
*
|
|
86
|
+
* @param format - Desired format ('json' | 'yaml')
|
|
87
|
+
* @returns Default file path
|
|
88
|
+
*/
|
|
89
|
+
export declare function getDefaultConfigPath(format: ConfigFormat): string;
|
|
90
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/config/generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AA+K/C;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAOlE;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOzE;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GAClB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CA4BvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IACjD,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,KAAK,CAAC,EAAE,OAAO,CAAA;CACf,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkCnE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAEjE"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config File Generator for iMessage Timeline
|
|
3
|
+
*
|
|
4
|
+
* Implements CONFIG--T03: Add Config Generation Command
|
|
5
|
+
* Generates starter configuration files with documentation comments
|
|
6
|
+
*/
|
|
7
|
+
import { constants } from 'node:fs';
|
|
8
|
+
import { access, writeFile } from 'node:fs/promises';
|
|
9
|
+
import yaml from 'js-yaml';
|
|
10
|
+
import { validateConfig } from './schema.js';
|
|
11
|
+
/**
|
|
12
|
+
* CONFIG-T03-AC03: Config template with inline documentation
|
|
13
|
+
*
|
|
14
|
+
* This template includes comments explaining each configuration option.
|
|
15
|
+
* The comments are YAML-compatible and will be preserved in YAML output.
|
|
16
|
+
*/
|
|
17
|
+
const CONFIG_TEMPLATE_WITH_DOCS = `# iMessage Timeline Configuration File
|
|
18
|
+
# Generated by: imessage-timeline init
|
|
19
|
+
#
|
|
20
|
+
# This file configures the iMessage message export and enrichment pipeline.
|
|
21
|
+
# Supports both YAML and JSON formats with environment variable substitution.
|
|
22
|
+
|
|
23
|
+
# Schema version (for future migrations)
|
|
24
|
+
version: "1.0"
|
|
25
|
+
|
|
26
|
+
# ============================================================================
|
|
27
|
+
# Attachment Resolution
|
|
28
|
+
# ============================================================================
|
|
29
|
+
|
|
30
|
+
# Directories to search for message attachments
|
|
31
|
+
# Multiple paths supported; first match wins
|
|
32
|
+
# Environment variable expansion supported: \${HOME}/Library/Messages
|
|
33
|
+
attachmentRoots:
|
|
34
|
+
- "~/Library/Messages/Attachments"
|
|
35
|
+
# Add additional search paths if needed:
|
|
36
|
+
# - "/path/to/imazing/backup/attachments"
|
|
37
|
+
|
|
38
|
+
# ============================================================================
|
|
39
|
+
# Gemini AI Configuration
|
|
40
|
+
# ============================================================================
|
|
41
|
+
|
|
42
|
+
gemini:
|
|
43
|
+
# Google Gemini API key (required for AI enrichment)
|
|
44
|
+
# Get your key from: https://makersuite.google.com/app/apikey
|
|
45
|
+
# Environment variable recommended for security: \${GEMINI_API_KEY}
|
|
46
|
+
apiKey: "\${GEMINI_API_KEY}"
|
|
47
|
+
|
|
48
|
+
# Gemini model to use for enrichment
|
|
49
|
+
# Options: gemini-1.5-pro, gemini-1.5-flash
|
|
50
|
+
# Default: gemini-1.5-pro (more accurate, slower)
|
|
51
|
+
model: "gemini-1.5-pro"
|
|
52
|
+
|
|
53
|
+
# Delay between API calls (milliseconds)
|
|
54
|
+
# Prevents rate limiting; adjust based on your quota
|
|
55
|
+
# Free tier: 60 requests/minute = 1000ms delay minimum
|
|
56
|
+
# Default: 1000 (1 second)
|
|
57
|
+
rateLimitDelay: 1000
|
|
58
|
+
|
|
59
|
+
# Maximum retries for failed API calls
|
|
60
|
+
# Applies exponential backoff with jitter
|
|
61
|
+
# Range: 0-10
|
|
62
|
+
# Default: 3
|
|
63
|
+
maxRetries: 3
|
|
64
|
+
|
|
65
|
+
# ============================================================================
|
|
66
|
+
# Firecrawl Configuration (Optional)
|
|
67
|
+
# ============================================================================
|
|
68
|
+
|
|
69
|
+
# firecrawl:
|
|
70
|
+
# # Firecrawl API key for enhanced link scraping (optional)
|
|
71
|
+
# # Get your key from: https://firecrawl.dev
|
|
72
|
+
# # Falls back to built-in scrapers if not provided
|
|
73
|
+
# apiKey: "\${FIRECRAWL_API_KEY}"
|
|
74
|
+
#
|
|
75
|
+
# # Enable/disable Firecrawl for link enrichment
|
|
76
|
+
# # Default: true (if apiKey provided)
|
|
77
|
+
# enabled: true
|
|
78
|
+
|
|
79
|
+
# ============================================================================
|
|
80
|
+
# Enrichment Pipeline Configuration
|
|
81
|
+
# ============================================================================
|
|
82
|
+
|
|
83
|
+
enrichment:
|
|
84
|
+
# Enable image analysis (captions, descriptions via Gemini Vision)
|
|
85
|
+
# HEIC/TIFF files converted to JPG for analysis
|
|
86
|
+
# Default: true
|
|
87
|
+
enableVisionAnalysis: true
|
|
88
|
+
|
|
89
|
+
# Enable audio transcription (voice memos, audio messages)
|
|
90
|
+
# Includes timestamps, speaker detection, and summaries
|
|
91
|
+
# Default: true
|
|
92
|
+
enableAudioTranscription: true
|
|
93
|
+
|
|
94
|
+
# Enable link context extraction (titles, summaries, metadata)
|
|
95
|
+
# Uses Firecrawl if configured, falls back to built-in scrapers
|
|
96
|
+
# Default: true
|
|
97
|
+
enableLinkEnrichment: true
|
|
98
|
+
|
|
99
|
+
# Cache directory for image previews (HEIC/TIFF → JPG)
|
|
100
|
+
# Prevents redundant conversions on re-runs
|
|
101
|
+
# Default: ./.cache/images
|
|
102
|
+
imageCacheDir: "./.cache/images"
|
|
103
|
+
|
|
104
|
+
# Checkpoint interval (messages per checkpoint)
|
|
105
|
+
# Lower = more frequent checkpoints = safer but slower
|
|
106
|
+
# Higher = faster but more work lost on interruption
|
|
107
|
+
# Range: 1-10000
|
|
108
|
+
# Default: 100
|
|
109
|
+
checkpointInterval: 100
|
|
110
|
+
|
|
111
|
+
# Force refresh of existing enrichments
|
|
112
|
+
# If true, re-enriches messages even if already enriched
|
|
113
|
+
# Default: false (skip already-enriched messages)
|
|
114
|
+
forceRefresh: false
|
|
115
|
+
|
|
116
|
+
# ============================================================================
|
|
117
|
+
# Markdown Rendering Configuration
|
|
118
|
+
# ============================================================================
|
|
119
|
+
|
|
120
|
+
render:
|
|
121
|
+
# Group messages by time-of-day (Morning, Afternoon, Evening)
|
|
122
|
+
# If false, renders as flat chronological list
|
|
123
|
+
# Default: true
|
|
124
|
+
groupByTimeOfDay: true
|
|
125
|
+
|
|
126
|
+
# Render replies as nested blockquotes under parent message
|
|
127
|
+
# If false, renders as flat list with reply indicators
|
|
128
|
+
# Default: true
|
|
129
|
+
renderRepliesAsNested: true
|
|
130
|
+
|
|
131
|
+
# Render tapbacks (reactions) as emoji (❤️, 😂, etc.)
|
|
132
|
+
# If false, renders as text descriptions
|
|
133
|
+
# Default: true
|
|
134
|
+
renderTapbacksAsEmoji: true
|
|
135
|
+
|
|
136
|
+
# Maximum nesting depth for nested replies
|
|
137
|
+
# Prevents infinite recursion in circular reply chains
|
|
138
|
+
# Range: 1-100
|
|
139
|
+
# Default: 10
|
|
140
|
+
maxNestingDepth: 10
|
|
141
|
+
`;
|
|
142
|
+
/**
|
|
143
|
+
* CONFIG-T03-AC03: Generate JSON template with comments
|
|
144
|
+
*
|
|
145
|
+
* JSON doesn't support inline comments, so we use a separate
|
|
146
|
+
* structure with documentation as values.
|
|
147
|
+
*/
|
|
148
|
+
const CONFIG_TEMPLATE_JSON = {
|
|
149
|
+
_comment: 'iMessage Timeline Configuration File',
|
|
150
|
+
_generated: 'Generated by: imessage-timeline init',
|
|
151
|
+
_docs: 'Full documentation: https://github.com/your-repo/imessage-timeline',
|
|
152
|
+
version: '1.0',
|
|
153
|
+
attachmentRoots: ['~/Library/Messages/Attachments'],
|
|
154
|
+
gemini: {
|
|
155
|
+
_comment: 'Get API key from: https://makersuite.google.com/app/apikey',
|
|
156
|
+
apiKey: '${GEMINI_API_KEY}',
|
|
157
|
+
model: 'gemini-1.5-pro',
|
|
158
|
+
rateLimitDelay: 1000,
|
|
159
|
+
maxRetries: 3,
|
|
160
|
+
},
|
|
161
|
+
enrichment: {
|
|
162
|
+
enableVisionAnalysis: true,
|
|
163
|
+
enableAudioTranscription: true,
|
|
164
|
+
enableLinkEnrichment: true,
|
|
165
|
+
imageCacheDir: './.cache/images',
|
|
166
|
+
checkpointInterval: 100,
|
|
167
|
+
forceRefresh: false,
|
|
168
|
+
},
|
|
169
|
+
render: {
|
|
170
|
+
groupByTimeOfDay: true,
|
|
171
|
+
renderRepliesAsNested: true,
|
|
172
|
+
renderTapbacksAsEmoji: true,
|
|
173
|
+
maxNestingDepth: 10,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* CONFIG-T03-AC02: Generate config file content in specified format
|
|
178
|
+
*
|
|
179
|
+
* @param format - Output format ('json' or 'yaml')
|
|
180
|
+
* @returns Formatted config file content as string
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const yamlContent = generateConfigContent('yaml')
|
|
185
|
+
* const jsonContent = generateConfigContent('json')
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
export function generateConfigContent(format) {
|
|
189
|
+
if (format === 'yaml') {
|
|
190
|
+
// Return YAML template with comments preserved
|
|
191
|
+
return CONFIG_TEMPLATE_WITH_DOCS;
|
|
192
|
+
}
|
|
193
|
+
// Return formatted JSON with indentation
|
|
194
|
+
return `${JSON.stringify(CONFIG_TEMPLATE_JSON, null, 2)}\n`;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* CONFIG-T03-AC04: Check if config file exists at path
|
|
198
|
+
*
|
|
199
|
+
* @param filePath - Path to check
|
|
200
|
+
* @returns True if file exists and is readable
|
|
201
|
+
*/
|
|
202
|
+
export async function configFileExists(filePath) {
|
|
203
|
+
try {
|
|
204
|
+
await access(filePath, constants.R_OK);
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* CONFIG-T03-AC05: Validate generated config content
|
|
213
|
+
*
|
|
214
|
+
* Parses the generated content and validates against schema
|
|
215
|
+
* to ensure the template produces valid config.
|
|
216
|
+
*
|
|
217
|
+
* @param content - Generated config content
|
|
218
|
+
* @param format - Format of content ('json' | 'yaml')
|
|
219
|
+
* @returns Validation result
|
|
220
|
+
*/
|
|
221
|
+
export function validateGeneratedConfig(content, format) {
|
|
222
|
+
try {
|
|
223
|
+
let parsed;
|
|
224
|
+
if (format === 'json') {
|
|
225
|
+
parsed = JSON.parse(content);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
parsed = yaml.load(content);
|
|
229
|
+
}
|
|
230
|
+
// Validate against schema (will throw if invalid)
|
|
231
|
+
// Note: This will fail validation because ${GEMINI_API_KEY} is a placeholder
|
|
232
|
+
// In production, we document this expected behavior
|
|
233
|
+
validateConfig(parsed);
|
|
234
|
+
return { valid: true };
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
if (error instanceof Error) {
|
|
238
|
+
return {
|
|
239
|
+
valid: false,
|
|
240
|
+
errors: [error.message],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
valid: false,
|
|
245
|
+
errors: ['Unknown validation error'],
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* CONFIG-T03-AC01: Generate config file at specified path
|
|
251
|
+
*
|
|
252
|
+
* Implements the core config generation logic with:
|
|
253
|
+
* - Format selection (YAML/JSON)
|
|
254
|
+
* - Overwrite protection
|
|
255
|
+
* - Content validation
|
|
256
|
+
*
|
|
257
|
+
* @param options - Generation options
|
|
258
|
+
* @param options.filePath - Output file path
|
|
259
|
+
* @param options.format - File format ('json' | 'yaml')
|
|
260
|
+
* @param options.force - Overwrite existing file without prompt
|
|
261
|
+
* @returns Success/failure result
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```typescript
|
|
265
|
+
* // Generate YAML config (default)
|
|
266
|
+
* await generateConfigFile({ filePath: './imessage-config.yaml' })
|
|
267
|
+
*
|
|
268
|
+
* // Generate JSON config
|
|
269
|
+
* await generateConfigFile({
|
|
270
|
+
* filePath: './imessage-config.json',
|
|
271
|
+
* format: 'json'
|
|
272
|
+
* })
|
|
273
|
+
*
|
|
274
|
+
* // Force overwrite
|
|
275
|
+
* await generateConfigFile({
|
|
276
|
+
* filePath: './imessage-config.yaml',
|
|
277
|
+
* force: true
|
|
278
|
+
* })
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
export async function generateConfigFile(options) {
|
|
282
|
+
const { filePath, format = 'yaml', force = false } = options;
|
|
283
|
+
// CONFIG-T03-AC04: Check for existing file
|
|
284
|
+
const exists = await configFileExists(filePath);
|
|
285
|
+
if (exists && !force) {
|
|
286
|
+
return {
|
|
287
|
+
success: false,
|
|
288
|
+
message: `Config file already exists at ${filePath}. Use --force to overwrite.`,
|
|
289
|
+
filePath,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
// CONFIG-T03-AC02 & AC03: Generate content with docs
|
|
293
|
+
const content = generateConfigContent(format);
|
|
294
|
+
// Write file
|
|
295
|
+
try {
|
|
296
|
+
await writeFile(filePath, content, 'utf-8');
|
|
297
|
+
return {
|
|
298
|
+
success: true,
|
|
299
|
+
message: `✅ Generated ${format.toUpperCase()} config at ${filePath}`,
|
|
300
|
+
filePath,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
return {
|
|
305
|
+
success: false,
|
|
306
|
+
message: `Failed to write config file: ${error instanceof Error ? error.message : String(error)}`,
|
|
307
|
+
filePath,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get default config file path for a given format
|
|
313
|
+
*
|
|
314
|
+
* @param format - Desired format ('json' | 'yaml')
|
|
315
|
+
* @returns Default file path
|
|
316
|
+
*/
|
|
317
|
+
export function getDefaultConfigPath(format) {
|
|
318
|
+
return format === 'yaml' ? './imessage-config.yaml' : './imessage-config.json';
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/config/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Loader for iMessage Timeline
|
|
3
|
+
*
|
|
4
|
+
* Implements CONFIG--T02: Implement Config Loader
|
|
5
|
+
* Loads config from YAML/JSON files with env var substitution and precedence
|
|
6
|
+
*/
|
|
7
|
+
import { type Config } from './schema.js';
|
|
8
|
+
/**
|
|
9
|
+
* CONFIG-T02-AC01: Discover config file in directory
|
|
10
|
+
*
|
|
11
|
+
* Checks files in order:
|
|
12
|
+
* 1. imessage-config.yaml
|
|
13
|
+
* 2. imessage-config.yml
|
|
14
|
+
* 3. imessage-config.json
|
|
15
|
+
*
|
|
16
|
+
* @param baseDir - Directory to search in (defaults to current directory)
|
|
17
|
+
* @returns Path to first existing config file, or null if none found
|
|
18
|
+
*/
|
|
19
|
+
export declare function discoverConfigFile(baseDir?: string): Promise<string | null>;
|
|
20
|
+
/**
|
|
21
|
+
* CONFIG-T02-AC01: Load and parse config file
|
|
22
|
+
*
|
|
23
|
+
* Supports JSON and YAML formats with auto-detection
|
|
24
|
+
*
|
|
25
|
+
* @param filePath - Path to config file
|
|
26
|
+
* @returns Parsed config object (unvalidated)
|
|
27
|
+
* @throws Error if file cannot be read or parsed
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadConfigFile(filePath: string): Promise<unknown>;
|
|
30
|
+
/**
|
|
31
|
+
* CONFIG-T02-AC03: Substitute environment variables in config
|
|
32
|
+
*
|
|
33
|
+
* Recursively replaces ${VAR_NAME} patterns with environment variable values
|
|
34
|
+
*
|
|
35
|
+
* @param obj - Config object (or primitive)
|
|
36
|
+
* @returns Object with env vars substituted
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // With process.env.GEMINI_API_KEY = 'secret123'
|
|
41
|
+
* substituteEnvVars({ apiKey: '${GEMINI_API_KEY}' })
|
|
42
|
+
* // => { apiKey: 'secret123' }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function substituteEnvVars(obj: unknown): unknown;
|
|
46
|
+
/**
|
|
47
|
+
* CONFIG-T02-AC02: Merge configuration with precedence
|
|
48
|
+
*
|
|
49
|
+
* Precedence (highest to lowest):
|
|
50
|
+
* 1. CLI options
|
|
51
|
+
* 2. Config file
|
|
52
|
+
* 3. Defaults (applied by Zod schema)
|
|
53
|
+
*
|
|
54
|
+
* @param fileConfig - Config loaded from file
|
|
55
|
+
* @param cliOptions - Options from CLI flags
|
|
56
|
+
* @returns Merged config object
|
|
57
|
+
*/
|
|
58
|
+
export declare function mergeConfig(fileConfig: Partial<Config>, cliOptions?: Partial<Config>): Partial<Config>;
|
|
59
|
+
/**
|
|
60
|
+
* CONFIG-T02: Main config loading function
|
|
61
|
+
*
|
|
62
|
+
* Loads configuration with the following precedence:
|
|
63
|
+
* 1. CLI options (highest priority)
|
|
64
|
+
* 2. Config file
|
|
65
|
+
* 3. Defaults from schema (lowest priority)
|
|
66
|
+
*
|
|
67
|
+
* @param options - Loading options
|
|
68
|
+
* @param options.configPath - Explicit config file path (optional)
|
|
69
|
+
* @param options.cliOptions - CLI options to merge (optional)
|
|
70
|
+
* @param options.skipCache - Force reload even if cached (optional)
|
|
71
|
+
* @returns Validated and merged configuration
|
|
72
|
+
* @throws Error if config is invalid or cannot be loaded
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* // Load with auto-discovery
|
|
77
|
+
* const config = await loadConfig()
|
|
78
|
+
*
|
|
79
|
+
* // Load specific file
|
|
80
|
+
* const config = await loadConfig({ configPath: './custom-config.yaml' })
|
|
81
|
+
*
|
|
82
|
+
* // Override with CLI options
|
|
83
|
+
* const config = await loadConfig({
|
|
84
|
+
* cliOptions: {
|
|
85
|
+
* gemini: { apiKey: 'override-key' }
|
|
86
|
+
* }
|
|
87
|
+
* })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare function loadConfig(options?: {
|
|
91
|
+
configPath?: string;
|
|
92
|
+
cliOptions?: Partial<Config>;
|
|
93
|
+
skipCache?: boolean;
|
|
94
|
+
}): Promise<Config>;
|
|
95
|
+
/**
|
|
96
|
+
* Clear the config cache
|
|
97
|
+
*
|
|
98
|
+
* Useful for testing or when config needs to be reloaded
|
|
99
|
+
*/
|
|
100
|
+
export declare function clearConfigCache(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Check if a config is currently cached
|
|
103
|
+
*
|
|
104
|
+
* @returns True if config is cached
|
|
105
|
+
*/
|
|
106
|
+
export declare function isConfigCached(): boolean;
|
|
107
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAAE,KAAK,MAAM,EAAsC,MAAM,aAAa,CAAA;AAS7E;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACvC,OAAO,GAAE,MAAsB,GAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqBxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA4BvE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CA+BvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAC1B,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,EAC3B,UAAU,GAAE,OAAO,CAAC,MAAM,CAAM,GAC9B,OAAO,CAAC,MAAM,CAAC,CAwCjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,UAAU,CAC/B,OAAO,GAAE;IACR,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAA;CACd,GACJ,OAAO,CAAC,MAAM,CAAC,CA+CjB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC"}
|