romm-uploader 0.1.1-beta.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.
Files changed (120) hide show
  1. package/.env.example +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +228 -0
  4. package/dist/cache/checksum-cache.d.ts +20 -0
  5. package/dist/cache/checksum-cache.d.ts.map +1 -0
  6. package/dist/cache/checksum-cache.js +134 -0
  7. package/dist/cache/checksum-cache.js.map +1 -0
  8. package/dist/checksum/compute-checksum.d.ts +16 -0
  9. package/dist/checksum/compute-checksum.d.ts.map +1 -0
  10. package/dist/checksum/compute-checksum.js +71 -0
  11. package/dist/checksum/compute-checksum.js.map +1 -0
  12. package/dist/cli.d.ts +7 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +165 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/config.d.ts +34 -0
  17. package/dist/config.d.ts.map +1 -0
  18. package/dist/config.js +95 -0
  19. package/dist/config.js.map +1 -0
  20. package/dist/files/discover-files.d.ts +9 -0
  21. package/dist/files/discover-files.d.ts.map +1 -0
  22. package/dist/files/discover-files.js +34 -0
  23. package/dist/files/discover-files.js.map +1 -0
  24. package/dist/files/discover-sources.d.ts +6 -0
  25. package/dist/files/discover-sources.d.ts.map +1 -0
  26. package/dist/files/discover-sources.js +69 -0
  27. package/dist/files/discover-sources.js.map +1 -0
  28. package/dist/files/discover-types.d.ts +8 -0
  29. package/dist/files/discover-types.d.ts.map +1 -0
  30. package/dist/files/discover-types.js +2 -0
  31. package/dist/files/discover-types.js.map +1 -0
  32. package/dist/files/file-info.d.ts +6 -0
  33. package/dist/files/file-info.d.ts.map +1 -0
  34. package/dist/files/file-info.js +44 -0
  35. package/dist/files/file-info.js.map +1 -0
  36. package/dist/output/planner.d.ts +6 -0
  37. package/dist/output/planner.d.ts.map +1 -0
  38. package/dist/output/planner.js +77 -0
  39. package/dist/output/planner.js.map +1 -0
  40. package/dist/output/records.d.ts +16 -0
  41. package/dist/output/records.d.ts.map +1 -0
  42. package/dist/output/records.js +31 -0
  43. package/dist/output/records.js.map +1 -0
  44. package/dist/output/reporter.d.ts +38 -0
  45. package/dist/output/reporter.d.ts.map +1 -0
  46. package/dist/output/reporter.js +66 -0
  47. package/dist/output/reporter.js.map +1 -0
  48. package/dist/romm/auth-cache.d.ts +27 -0
  49. package/dist/romm/auth-cache.d.ts.map +1 -0
  50. package/dist/romm/auth-cache.js +115 -0
  51. package/dist/romm/auth-cache.js.map +1 -0
  52. package/dist/romm/client-http.d.ts +5 -0
  53. package/dist/romm/client-http.d.ts.map +1 -0
  54. package/dist/romm/client-http.js +44 -0
  55. package/dist/romm/client-http.js.map +1 -0
  56. package/dist/romm/client-mappers.d.ts +18 -0
  57. package/dist/romm/client-mappers.d.ts.map +1 -0
  58. package/dist/romm/client-mappers.js +66 -0
  59. package/dist/romm/client-mappers.js.map +1 -0
  60. package/dist/romm/client-session.d.ts +23 -0
  61. package/dist/romm/client-session.d.ts.map +1 -0
  62. package/dist/romm/client-session.js +116 -0
  63. package/dist/romm/client-session.js.map +1 -0
  64. package/dist/romm/client-types.d.ts +29 -0
  65. package/dist/romm/client-types.d.ts.map +1 -0
  66. package/dist/romm/client-types.js +2 -0
  67. package/dist/romm/client-types.js.map +1 -0
  68. package/dist/romm/client.d.ts +86 -0
  69. package/dist/romm/client.d.ts.map +1 -0
  70. package/dist/romm/client.js +168 -0
  71. package/dist/romm/client.js.map +1 -0
  72. package/dist/romm/upload-duplicate-check.d.ts +16 -0
  73. package/dist/romm/upload-duplicate-check.d.ts.map +1 -0
  74. package/dist/romm/upload-duplicate-check.js +16 -0
  75. package/dist/romm/upload-duplicate-check.js.map +1 -0
  76. package/dist/romm/upload-utils.d.ts +9 -0
  77. package/dist/romm/upload-utils.d.ts.map +1 -0
  78. package/dist/romm/upload-utils.js +31 -0
  79. package/dist/romm/upload-utils.js.map +1 -0
  80. package/dist/types.d.ts +98 -0
  81. package/dist/types.d.ts.map +1 -0
  82. package/dist/types.js +5 -0
  83. package/dist/types.js.map +1 -0
  84. package/dist/workflow/create-client.d.ts +7 -0
  85. package/dist/workflow/create-client.d.ts.map +1 -0
  86. package/dist/workflow/create-client.js +19 -0
  87. package/dist/workflow/create-client.js.map +1 -0
  88. package/dist/workflow/discover-input.d.ts +6 -0
  89. package/dist/workflow/discover-input.d.ts.map +1 -0
  90. package/dist/workflow/discover-input.js +14 -0
  91. package/dist/workflow/discover-input.js.map +1 -0
  92. package/dist/workflow/io.d.ts +6 -0
  93. package/dist/workflow/io.d.ts.map +1 -0
  94. package/dist/workflow/io.js +13 -0
  95. package/dist/workflow/io.js.map +1 -0
  96. package/dist/workflow/process-dry-file.d.ts +26 -0
  97. package/dist/workflow/process-dry-file.d.ts.map +1 -0
  98. package/dist/workflow/process-dry-file.js +51 -0
  99. package/dist/workflow/process-dry-file.js.map +1 -0
  100. package/dist/workflow/process-roms.d.ts +15 -0
  101. package/dist/workflow/process-roms.d.ts.map +1 -0
  102. package/dist/workflow/process-roms.js +26 -0
  103. package/dist/workflow/process-roms.js.map +1 -0
  104. package/dist/workflow/process-upload-file.d.ts +22 -0
  105. package/dist/workflow/process-upload-file.d.ts.map +1 -0
  106. package/dist/workflow/process-upload-file.js +55 -0
  107. package/dist/workflow/process-upload-file.js.map +1 -0
  108. package/dist/workflow/resolve-checksums.d.ts +10 -0
  109. package/dist/workflow/resolve-checksums.d.ts.map +1 -0
  110. package/dist/workflow/resolve-checksums.js +28 -0
  111. package/dist/workflow/resolve-checksums.js.map +1 -0
  112. package/dist/workflow/run-dry.d.ts +6 -0
  113. package/dist/workflow/run-dry.d.ts.map +1 -0
  114. package/dist/workflow/run-dry.js +96 -0
  115. package/dist/workflow/run-dry.js.map +1 -0
  116. package/dist/workflow/run-upload.d.ts +6 -0
  117. package/dist/workflow/run-upload.d.ts.map +1 -0
  118. package/dist/workflow/run-upload.js +131 -0
  119. package/dist/workflow/run-upload.js.map +1 -0
  120. package/package.json +68 -0
package/dist/cli.js ADDED
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * RomM Uploader CLI
4
+ * Linux-first TypeScript CLI for uploading ROMs to RomM
5
+ */
6
+ import { Command } from 'commander';
7
+ import { resolveConfig, validateConfig } from './config.js';
8
+ import { Reporter } from './output/reporter.js';
9
+ import { createClient } from './workflow/create-client.js';
10
+ import { runDryMode } from './workflow/run-dry.js';
11
+ import { runUploadMode } from './workflow/run-upload.js';
12
+ const program = new Command();
13
+ program
14
+ .name('romm-uploader')
15
+ .description('Upload ROMs to your RomM instance')
16
+ .version('0.1.0')
17
+ .argument('[paths...]', 'ROM file or directory paths to process')
18
+ // Core connection options
19
+ .option('--base-url <url>', 'ROMM base URL (or ROMM_BASE_URL env var)')
20
+ .option('--username <user>', 'ROMM username (or ROMM_USERNAME env var)')
21
+ .option('--password <pass>', 'ROMM password (or ROMM_PASSWORD env var)')
22
+ // Platform options
23
+ .option('--platform <value>', 'Target platform (slug, name, or numeric ID)')
24
+ // Explicit input options
25
+ .option('--upload-file <path>', 'Upload a specific file (repeatable)', collect, [])
26
+ .option('--upload-dir <path>', 'Upload all files in directory (repeatable)', collect, [])
27
+ .option('--glob <pattern>', 'Upload files matching glob pattern (repeatable)', collect, [])
28
+ // Checksum options
29
+ .option('--checksum <algo>', 'Additional hash algorithm for reporting (repeatable)', collect, [])
30
+ .option('--cache-enabled <true|false>', 'Enable disk checksum cache', parseBoolean, true)
31
+ .option('--cache-max-mb <n>', 'Checksum cache size cap in MB', parseInteger, 4)
32
+ .option('--cache-path <path>', 'Override checksum cache file location')
33
+ // Auth options
34
+ .option('--auth-cache-enabled <true|false>', 'Enable auth token cache', parseBoolean, true)
35
+ .option('--auth-cache-path <path>', 'Override auth token cache file location')
36
+ .option('--auth-reauth-skew-seconds <n>', 'Refresh/re-auth early window before expiry', parseInteger, 60)
37
+ // Request options
38
+ .option('--request-timeout-seconds <n>', 'HTTP request timeout', parseInteger, 60)
39
+ .option('--retry-count <n>', 'Retry attempts for transient failures', parseInteger, 0)
40
+ // Behavior options
41
+ .option('--recursive', 'Include nested files when directory path passed', false)
42
+ .option('--dry-run', 'Run checksum + existence checks only, no upload', false)
43
+ .option('--concurrency <n>', 'Parallel file processing count', parseInteger, 3)
44
+ // Output options
45
+ .option('--json', 'Output structured JSON for scripting', false)
46
+ .option('--verbose', 'Enable detailed operational output', false)
47
+ .option('--list-platforms', 'Print available platforms and exit', false);
48
+ /**
49
+ * Collect multiple option values into an array
50
+ */
51
+ function collect(value, previous) {
52
+ return previous.concat([value]);
53
+ }
54
+ /**
55
+ * Parse boolean option value
56
+ */
57
+ function parseBoolean(value) {
58
+ return value.toLowerCase() === 'true';
59
+ }
60
+ /**
61
+ * Parse integer option value
62
+ */
63
+ function parseInteger(value) {
64
+ return Number.parseInt(value, 10);
65
+ }
66
+ /**
67
+ * Convert Commander options to our CliOptions format
68
+ */
69
+ function convertOptions(opts, paths) {
70
+ return resolveConfig({
71
+ baseUrl: opts.baseUrl,
72
+ username: opts.username,
73
+ password: opts.password,
74
+ platform: opts.platform,
75
+ paths,
76
+ uploadFiles: opts.uploadFile,
77
+ uploadDirs: opts.uploadDir,
78
+ globs: opts.glob,
79
+ checksum: opts.checksum,
80
+ cacheEnabled: opts.cacheEnabled,
81
+ cacheMaxMb: opts.cacheMaxMb,
82
+ cachePath: opts.cachePath,
83
+ authCacheEnabled: opts.authCacheEnabled,
84
+ authCachePath: opts.authCachePath,
85
+ authReauthSkewSeconds: opts.authReauthSkewSeconds,
86
+ requestTimeoutSeconds: opts.requestTimeoutSeconds,
87
+ retryCount: opts.retryCount,
88
+ recursive: opts.recursive,
89
+ dryRun: opts.dryRun,
90
+ concurrency: opts.concurrency,
91
+ json: opts.json,
92
+ verbose: opts.verbose,
93
+ listPlatforms: opts.listPlatforms,
94
+ });
95
+ }
96
+ /**
97
+ * Handle --list-platforms command
98
+ */
99
+ async function handleListPlatforms(config) {
100
+ const reporter = new Reporter({ json: config.json, verbose: config.verbose });
101
+ const client = await createClient(config);
102
+ if (!config.password) {
103
+ console.error('error: password required (--password or ROMM_PASSWORD)');
104
+ console.error('error: cached tokens are not yet supported for this operation');
105
+ return 2;
106
+ }
107
+ try {
108
+ await client.authenticate();
109
+ const platforms = await client.getPlatforms();
110
+ reporter.reportPlatforms(platforms);
111
+ return 0;
112
+ }
113
+ catch (error) {
114
+ console.error('error: failed to list platforms:', error instanceof Error ? error.message : error);
115
+ return 1;
116
+ }
117
+ }
118
+ /**
119
+ * Main entry point
120
+ */
121
+ async function main() {
122
+ program.parse();
123
+ const paths = program.args;
124
+ const opts = program.opts();
125
+ const config = convertOptions(opts, paths);
126
+ if (!config.dryRun) {
127
+ const errors = validateConfig(config);
128
+ if (errors.length > 0) {
129
+ console.error('error: configuration invalid:');
130
+ errors.forEach((err) => console.error(` - ${err}`));
131
+ process.exit(2);
132
+ }
133
+ }
134
+ else {
135
+ const hasFiles = config.paths.length > 0 ||
136
+ config.uploadFiles.length > 0 ||
137
+ config.uploadDirs.length > 0 ||
138
+ config.globs.length > 0;
139
+ if (!hasFiles) {
140
+ console.error('error: no files specified (use paths, --upload-file, --upload-dir, or --glob)');
141
+ process.exit(2);
142
+ }
143
+ }
144
+ if (config.listPlatforms) {
145
+ process.exit(await handleListPlatforms(config));
146
+ }
147
+ if (config.dryRun) {
148
+ process.exit(await runDryMode(config));
149
+ }
150
+ if (!config.platform) {
151
+ console.error('error: --platform is required for upload');
152
+ console.error('hint: use --list-platforms');
153
+ process.exit(2);
154
+ }
155
+ if (!config.password) {
156
+ console.error('error: password required (--password or ROMM_PASSWORD)');
157
+ process.exit(2);
158
+ }
159
+ process.exit(await runUploadMode(config));
160
+ }
161
+ main().catch((error) => {
162
+ console.error('error: fatal:', error);
163
+ process.exit(1);
164
+ });
165
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export { CliOptions } from './types.js';
2
+ /**
3
+ * Configuration management for romm-uploader
4
+ * Handles CLI args and environment variables with proper precedence
5
+ */
6
+ import { CliOptions } from './types.js';
7
+ /** Default configuration values */
8
+ export declare const defaults: {
9
+ readonly cacheEnabled: true;
10
+ readonly cacheMaxMb: 4;
11
+ readonly authCacheEnabled: true;
12
+ readonly authReauthSkewSeconds: 60;
13
+ readonly requestTimeoutSeconds: 60;
14
+ readonly retryCount: 0;
15
+ readonly concurrency: 3;
16
+ };
17
+ /**
18
+ * Resolve configuration from CLI options and environment variables
19
+ * CLI options take precedence over environment variables
20
+ */
21
+ export declare function resolveConfig(cliOptions: Partial<CliOptions>): CliOptions;
22
+ /**
23
+ * Validate configuration and return any errors
24
+ */
25
+ export declare function validateConfig(config: CliOptions): string[];
26
+ /**
27
+ * Get default auth cache path based on XDG spec
28
+ */
29
+ export declare function getDefaultAuthCachePath(): string;
30
+ /**
31
+ * Get default checksum cache path based on XDG spec
32
+ */
33
+ export declare function getDefaultChecksumCachePath(): string;
34
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,mCAAmC;AACnC,eAAO,MAAM,QAAQ;;;;;;;;CAQX,CAAC;AASX;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CA6CzE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAgB3D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAMhD;AAED;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,CAMpD"}
package/dist/config.js ADDED
@@ -0,0 +1,95 @@
1
+ /** Default configuration values */
2
+ export const defaults = {
3
+ cacheEnabled: true,
4
+ cacheMaxMb: 4,
5
+ authCacheEnabled: true,
6
+ authReauthSkewSeconds: 60,
7
+ requestTimeoutSeconds: 60,
8
+ retryCount: 0,
9
+ concurrency: 3,
10
+ };
11
+ /** Environment variable names */
12
+ const envVars = {
13
+ baseUrl: 'ROMM_BASE_URL',
14
+ username: 'ROMM_USERNAME',
15
+ password: 'ROMM_PASSWORD',
16
+ };
17
+ /**
18
+ * Resolve configuration from CLI options and environment variables
19
+ * CLI options take precedence over environment variables
20
+ */
21
+ export function resolveConfig(cliOptions) {
22
+ const baseUrl = cliOptions.baseUrl ?? process.env[envVars.baseUrl] ?? '';
23
+ const username = cliOptions.username ?? process.env[envVars.username] ?? '';
24
+ const password = cliOptions.password ?? process.env[envVars.password];
25
+ return {
26
+ // Core connection
27
+ baseUrl,
28
+ username,
29
+ password,
30
+ // Platform
31
+ platform: cliOptions.platform,
32
+ // Input (arrays default to empty)
33
+ paths: cliOptions.paths ?? [],
34
+ uploadFiles: cliOptions.uploadFiles ?? [],
35
+ uploadDirs: cliOptions.uploadDirs ?? [],
36
+ globs: cliOptions.globs ?? [],
37
+ // Checksum
38
+ checksum: cliOptions.checksum ?? [],
39
+ cacheEnabled: cliOptions.cacheEnabled ?? defaults.cacheEnabled,
40
+ cacheMaxMb: cliOptions.cacheMaxMb ?? defaults.cacheMaxMb,
41
+ cachePath: cliOptions.cachePath,
42
+ // Auth
43
+ authCacheEnabled: cliOptions.authCacheEnabled ?? defaults.authCacheEnabled,
44
+ authCachePath: cliOptions.authCachePath,
45
+ authReauthSkewSeconds: cliOptions.authReauthSkewSeconds ?? defaults.authReauthSkewSeconds,
46
+ // Request
47
+ requestTimeoutSeconds: cliOptions.requestTimeoutSeconds ?? defaults.requestTimeoutSeconds,
48
+ retryCount: cliOptions.retryCount ?? defaults.retryCount,
49
+ // Behavior
50
+ recursive: cliOptions.recursive ?? false,
51
+ dryRun: cliOptions.dryRun ?? false,
52
+ concurrency: cliOptions.concurrency ?? defaults.concurrency,
53
+ // Output
54
+ json: cliOptions.json ?? false,
55
+ verbose: cliOptions.verbose ?? false,
56
+ listPlatforms: cliOptions.listPlatforms ?? false,
57
+ };
58
+ }
59
+ /**
60
+ * Validate configuration and return any errors
61
+ */
62
+ export function validateConfig(config) {
63
+ const errors = [];
64
+ if (!config.baseUrl) {
65
+ errors.push('Missing required option: --base-url (or ROMM_BASE_URL env var)');
66
+ }
67
+ if (!config.username) {
68
+ errors.push('Missing required option: --username (or ROMM_USERNAME env var)');
69
+ }
70
+ // Password is required unless we're just listing platforms (and even then we need auth per PLAN)
71
+ // Per PLAN: "all ROMM API operations require authentication, including --list-platforms"
72
+ // But password may be omitted when a valid cached token exists
73
+ return errors;
74
+ }
75
+ /**
76
+ * Get default auth cache path based on XDG spec
77
+ */
78
+ export function getDefaultAuthCachePath() {
79
+ const xdgCacheHome = process.env.XDG_CACHE_HOME;
80
+ if (xdgCacheHome) {
81
+ return `${xdgCacheHome}/romm-uploader/auth-token-cache.json`;
82
+ }
83
+ return `${process.env.HOME ?? '~'}/.cache/romm-uploader/auth-token-cache.json`;
84
+ }
85
+ /**
86
+ * Get default checksum cache path based on XDG spec
87
+ */
88
+ export function getDefaultChecksumCachePath() {
89
+ const xdgCacheHome = process.env.XDG_CACHE_HOME;
90
+ if (xdgCacheHome) {
91
+ return `${xdgCacheHome}/romm-uploader/checksum-cache.json`;
92
+ }
93
+ return `${process.env.HOME ?? '~'}/.cache/romm-uploader/checksum-cache.json`;
94
+ }
95
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { FileInfo } from '../types.js';
2
+ import { DiscoverOptions } from './discover-types.js';
3
+ /**
4
+ * Discover files from all input sources
5
+ * Per PLAN: positional paths, --upload-file, --upload-dir, --glob
6
+ * Returns merged, deduplicated list
7
+ */
8
+ export declare function discoverFiles(options: DiscoverOptions): Promise<FileInfo[]>;
9
+ //# sourceMappingURL=discover-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover-files.d.ts","sourceRoot":"","sources":["../../src/files/discover-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAqBtD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAoBjF"}
@@ -0,0 +1,34 @@
1
+ import { discoverFromGlobs, discoverFromPaths, discoverFromUploadDirs, discoverFromUploadFiles, } from './discover-sources.js';
2
+ function deduplicateFiles(files) {
3
+ const seen = new Set();
4
+ const unique = [];
5
+ for (const file of files) {
6
+ if (seen.has(file.absolutePath))
7
+ continue;
8
+ seen.add(file.absolutePath);
9
+ unique.push(file);
10
+ }
11
+ return unique;
12
+ }
13
+ /**
14
+ * Discover files from all input sources
15
+ * Per PLAN: positional paths, --upload-file, --upload-dir, --glob
16
+ * Returns merged, deduplicated list
17
+ */
18
+ export async function discoverFiles(options) {
19
+ const allFiles = [];
20
+ if (options.paths.length > 0) {
21
+ allFiles.push(...(await discoverFromPaths(options.paths, options.recursive)));
22
+ }
23
+ if (options.uploadFiles.length > 0) {
24
+ allFiles.push(...(await discoverFromUploadFiles(options.uploadFiles)));
25
+ }
26
+ if (options.uploadDirs.length > 0) {
27
+ allFiles.push(...(await discoverFromUploadDirs(options.uploadDirs, options.recursive)));
28
+ }
29
+ if (options.globs.length > 0) {
30
+ allFiles.push(...(await discoverFromGlobs(options.globs)));
31
+ }
32
+ return deduplicateFiles(allFiles);
33
+ }
34
+ //# sourceMappingURL=discover-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover-files.js","sourceRoot":"","sources":["../../src/files/discover-files.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAE/B,SAAS,gBAAgB,CAAC,KAAiB;IACzC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,MAAM,GAAe,EAAE,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC;YAAE,SAAS;QAC1C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAwB;IAC1D,MAAM,QAAQ,GAAe,EAAE,CAAC;IAEhC,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,iBAAiB,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,uBAAuB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,sBAAsB,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC1F,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { FileInfo } from '../types.js';
2
+ export declare function discoverFromPaths(paths: string[], recursive: boolean): Promise<FileInfo[]>;
3
+ export declare function discoverFromUploadFiles(filePaths: string[]): Promise<FileInfo[]>;
4
+ export declare function discoverFromUploadDirs(dirPaths: string[], recursive: boolean): Promise<FileInfo[]>;
5
+ export declare function discoverFromGlobs(patterns: string[]): Promise<FileInfo[]>;
6
+ //# sourceMappingURL=discover-sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover-sources.d.ts","sourceRoot":"","sources":["../../src/files/discover-sources.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CA2BhG;AAED,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAWtF;AAED,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAAE,EAClB,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAuBrB;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAQ/E"}
@@ -0,0 +1,69 @@
1
+ import { promises as fs } from 'fs';
2
+ import { resolve } from 'path';
3
+ import fg from 'fast-glob';
4
+ import { collectFileInfos, listDirectoryFiles, toFileInfo, warn } from './file-info.js';
5
+ export async function discoverFromPaths(paths, recursive) {
6
+ const files = [];
7
+ for (const inputPath of paths) {
8
+ const absolutePath = resolve(inputPath);
9
+ try {
10
+ const stats = await fs.stat(absolutePath);
11
+ if (stats.isFile()) {
12
+ const info = await toFileInfo(absolutePath);
13
+ if (info)
14
+ files.push(info);
15
+ continue;
16
+ }
17
+ if (stats.isDirectory()) {
18
+ const discovered = await listDirectoryFiles(absolutePath, recursive);
19
+ files.push(...(await collectFileInfos(discovered)));
20
+ }
21
+ }
22
+ catch (error) {
23
+ warn(`Cannot access ${inputPath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
24
+ }
25
+ }
26
+ return files;
27
+ }
28
+ export async function discoverFromUploadFiles(filePaths) {
29
+ const files = [];
30
+ for (const filePath of filePaths) {
31
+ const info = await toFileInfo(filePath);
32
+ if (info) {
33
+ files.push(info);
34
+ }
35
+ else {
36
+ warn(`Cannot read file ${filePath}`);
37
+ }
38
+ }
39
+ return files;
40
+ }
41
+ export async function discoverFromUploadDirs(dirPaths, recursive) {
42
+ const files = [];
43
+ for (const dirPath of dirPaths) {
44
+ try {
45
+ const absoluteDir = resolve(dirPath);
46
+ const stats = await fs.stat(absoluteDir);
47
+ if (!stats.isDirectory()) {
48
+ warn(`${dirPath} is not a directory`);
49
+ continue;
50
+ }
51
+ const discovered = await listDirectoryFiles(absoluteDir, recursive);
52
+ files.push(...(await collectFileInfos(discovered)));
53
+ }
54
+ catch (error) {
55
+ warn(`Cannot access directory ${dirPath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
56
+ }
57
+ }
58
+ return files;
59
+ }
60
+ export async function discoverFromGlobs(patterns) {
61
+ const globFiles = await fg(patterns, {
62
+ absolute: true,
63
+ onlyFiles: true,
64
+ dot: false,
65
+ });
66
+ globFiles.sort();
67
+ return collectFileInfos(globFiles);
68
+ }
69
+ //# sourceMappingURL=discover-sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover-sources.js","sourceRoot":"","sources":["../../src/files/discover-sources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,MAAM,WAAW,CAAC;AAE3B,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAExF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAe,EAAE,SAAkB;IACzE,MAAM,KAAK,GAAe,EAAE,CAAC;IAE7B,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QAExC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAE1C,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBACnB,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,YAAY,CAAC,CAAC;gBAC5C,IAAI,IAAI;oBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC3B,SAAS;YACX,CAAC;YAED,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;gBACrE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CACF,iBAAiB,SAAS,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAC1F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,SAAmB;IAC/D,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,IAAI,EAAE,CAAC;YACT,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,oBAAoB,QAAQ,EAAE,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,QAAkB,EAClB,SAAkB;IAElB,MAAM,KAAK,GAAe,EAAE,CAAC;IAE7B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;YACrC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAEzC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACzB,IAAI,CAAC,GAAG,OAAO,qBAAqB,CAAC,CAAC;gBACtC,SAAS;YACX,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YACpE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CACF,2BAA2B,OAAO,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAClG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,QAAkB;IACxD,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,QAAQ,EAAE;QACnC,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,IAAI;QACf,GAAG,EAAE,KAAK;KACX,CAAC,CAAC;IACH,SAAS,CAAC,IAAI,EAAE,CAAC;IACjB,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface DiscoverOptions {
2
+ paths: string[];
3
+ uploadFiles: string[];
4
+ uploadDirs: string[];
5
+ globs: string[];
6
+ recursive: boolean;
7
+ }
8
+ //# sourceMappingURL=discover-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover-types.d.ts","sourceRoot":"","sources":["../../src/files/discover-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACpB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=discover-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover-types.js","sourceRoot":"","sources":["../../src/files/discover-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ import { FileInfo } from '../types.js';
2
+ export declare function warn(message: string): void;
3
+ export declare function toFileInfo(filePath: string): Promise<FileInfo | null>;
4
+ export declare function collectFileInfos(paths: string[]): Promise<FileInfo[]>;
5
+ export declare function listDirectoryFiles(directory: string, recursive: boolean): Promise<string[]>;
6
+ //# sourceMappingURL=file-info.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-info.d.ts","sourceRoot":"","sources":["../../src/files/file-info.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAc3E;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAS3E;AAED,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUjG"}
@@ -0,0 +1,44 @@
1
+ import { promises as fs } from 'fs';
2
+ import { resolve } from 'path';
3
+ import fg from 'fast-glob';
4
+ export function warn(message) {
5
+ console.warn(`⚠️ Warning: ${message}`);
6
+ }
7
+ export async function toFileInfo(filePath) {
8
+ try {
9
+ const absolutePath = resolve(filePath);
10
+ const stats = await fs.stat(absolutePath);
11
+ if (!stats.isFile())
12
+ return null;
13
+ return {
14
+ absolutePath,
15
+ size: stats.size,
16
+ mtime: stats.mtime.getTime(),
17
+ };
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ export async function collectFileInfos(paths) {
24
+ const results = [];
25
+ for (const filePath of paths) {
26
+ const info = await toFileInfo(filePath);
27
+ if (info) {
28
+ results.push(info);
29
+ }
30
+ }
31
+ return results;
32
+ }
33
+ export async function listDirectoryFiles(directory, recursive) {
34
+ const pattern = recursive ? '**/*' : '*';
35
+ const files = await fg(pattern, {
36
+ cwd: directory,
37
+ absolute: true,
38
+ onlyFiles: true,
39
+ dot: false,
40
+ });
41
+ files.sort();
42
+ return files;
43
+ }
44
+ //# sourceMappingURL=file-info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-info.js","sourceRoot":"","sources":["../../src/files/file-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,MAAM,WAAW,CAAC;AAG3B,MAAM,UAAU,IAAI,CAAC,OAAe;IAClC,OAAO,CAAC,IAAI,CAAC,gBAAgB,OAAO,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB;IAC/C,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,OAAO,IAAI,CAAC;QAEjC,OAAO;YACL,YAAY;YACZ,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE;SAC7B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAe;IACpD,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAiB,EAAE,SAAkB;IAC5E,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;IACzC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,EAAE;QAC9B,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,IAAI;QACf,GAAG,EAAE,KAAK;KACX,CAAC,CAAC;IACH,KAAK,CAAC,IAAI,EAAE,CAAC;IACb,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Print planned actions based on configuration
3
+ */
4
+ import type { CliOptions } from '../types.js';
5
+ export declare function printPlannedActions(config: CliOptions): void;
6
+ //# sourceMappingURL=planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/output/planner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAmF5D"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Print planned actions based on configuration
3
+ */
4
+ export function printPlannedActions(config) {
5
+ process.stderr.write('\nplan:\n');
6
+ // Connection info
7
+ process.stderr.write(`base_url=${config.baseUrl || '(not set)'}\n`);
8
+ process.stderr.write(`username=${config.username || '(not set)'}\n`);
9
+ process.stderr.write(`Password: ${config.password ? '(provided)' : '(not set; cached token may be used if available)'}`);
10
+ process.stderr.write('\n');
11
+ // Platform
12
+ if (config.platform) {
13
+ process.stderr.write(`platform=${config.platform}\n`);
14
+ }
15
+ else if (config.listPlatforms) {
16
+ process.stderr.write('mode=list-platforms\n');
17
+ }
18
+ else {
19
+ process.stderr.write('platform=(not set)\n');
20
+ }
21
+ // Input sources
22
+ process.stderr.write('inputs:\n');
23
+ if (config.paths.length > 0) {
24
+ process.stderr.write(` paths=${config.paths.length}\n`);
25
+ config.paths.forEach((p) => process.stderr.write(` ${p}\n`));
26
+ }
27
+ if (config.uploadFiles.length > 0) {
28
+ process.stderr.write(` upload_file=${config.uploadFiles.length}\n`);
29
+ config.uploadFiles.forEach((p) => process.stderr.write(` ${p}\n`));
30
+ }
31
+ if (config.uploadDirs.length > 0) {
32
+ process.stderr.write(` upload_dir=${config.uploadDirs.length}\n`);
33
+ config.uploadDirs.forEach((p) => process.stderr.write(` ${p}\n`));
34
+ }
35
+ if (config.globs.length > 0) {
36
+ process.stderr.write(` glob=${config.globs.length}\n`);
37
+ config.globs.forEach((p) => process.stderr.write(` ${p}\n`));
38
+ }
39
+ if (config.paths.length === 0 &&
40
+ config.uploadFiles.length === 0 &&
41
+ config.uploadDirs.length === 0 &&
42
+ config.globs.length === 0 &&
43
+ !config.listPlatforms) {
44
+ process.stderr.write(' (none)\n');
45
+ }
46
+ // Checksum settings
47
+ process.stderr.write('checksum:\n');
48
+ process.stderr.write(` cache_enabled=${config.cacheEnabled}\n`);
49
+ process.stderr.write(` cache_max_mb=${config.cacheMaxMb}\n`);
50
+ if (config.cachePath) {
51
+ process.stderr.write(` cache_path=${config.cachePath}\n`);
52
+ }
53
+ if (config.checksum.length > 0) {
54
+ process.stderr.write(` additional=${config.checksum.join(', ')}\n`);
55
+ }
56
+ // Auth settings
57
+ process.stderr.write('auth:\n');
58
+ process.stderr.write(` cache_enabled=${config.authCacheEnabled}\n`);
59
+ if (config.authCachePath) {
60
+ process.stderr.write(` cache_path=${config.authCachePath}\n`);
61
+ }
62
+ process.stderr.write(` reauth_skew_seconds=${config.authReauthSkewSeconds}\n`);
63
+ // Request settings
64
+ process.stderr.write('request:\n');
65
+ process.stderr.write(` timeout_seconds=${config.requestTimeoutSeconds}\n`);
66
+ process.stderr.write(` retry_count=${config.retryCount}\n`);
67
+ // Behavior
68
+ process.stderr.write('behavior:\n');
69
+ process.stderr.write(` recursive=${config.recursive}\n`);
70
+ process.stderr.write(` dry_run=${config.dryRun}\n`);
71
+ process.stderr.write(` concurrency=${config.concurrency}\n`);
72
+ // Output
73
+ process.stderr.write('output:\n');
74
+ process.stderr.write(` json=${config.json}\n`);
75
+ process.stderr.write(` verbose=${config.verbose}\n`);
76
+ }
77
+ //# sourceMappingURL=planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/output/planner.ts"],"names":[],"mappings":"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"}