@dollhousemcp/mcp-server 2.0.35 → 2.0.36

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 (31) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/elements/base/BaseElementManager.d.ts.map +1 -1
  3. package/dist/elements/base/BaseElementManager.js +6 -2
  4. package/dist/elements/memories/Memory.d.ts.map +1 -1
  5. package/dist/elements/memories/Memory.js +9 -2
  6. package/dist/elements/memories/MemoryManager.d.ts +13 -0
  7. package/dist/elements/memories/MemoryManager.d.ts.map +1 -1
  8. package/dist/elements/memories/MemoryManager.js +57 -44
  9. package/dist/elements/memories/constants.js +2 -2
  10. package/dist/generated/version.d.ts +2 -2
  11. package/dist/generated/version.js +3 -3
  12. package/dist/handlers/GitHubAuthHandler.d.ts +12 -0
  13. package/dist/handlers/GitHubAuthHandler.d.ts.map +1 -1
  14. package/dist/handlers/GitHubAuthHandler.js +303 -60
  15. package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts +62 -0
  16. package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts.map +1 -1
  17. package/dist/handlers/mcp-aql/MCPAQLHandler.js +209 -34
  18. package/dist/security/contentValidator.d.ts +32 -1
  19. package/dist/security/contentValidator.d.ts.map +1 -1
  20. package/dist/security/contentValidator.js +74 -31
  21. package/dist/security/secureYamlParser.d.ts.map +1 -1
  22. package/dist/security/secureYamlParser.js +5 -2
  23. package/dist/security/tokenManager.d.ts +1 -1
  24. package/dist/security/tokenManager.d.ts.map +1 -1
  25. package/dist/security/tokenManager.js +10 -7
  26. package/dist/storage/MemoryMetadataExtractor.d.ts +4 -1
  27. package/dist/storage/MemoryMetadataExtractor.d.ts.map +1 -1
  28. package/dist/storage/MemoryMetadataExtractor.js +7 -3
  29. package/oauth-helper.mjs +233 -92
  30. package/package.json +1 -1
  31. package/server.json +2 -2
@@ -9,10 +9,14 @@
9
9
  */
10
10
  import { SecureYamlParser } from '../security/secureYamlParser.js';
11
11
  import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
12
+ import { MEMORY_CONSTANTS } from '../elements/memories/constants.js';
12
13
  import { logger } from '../utils/logger.js';
13
14
  export class MemoryMetadataExtractor {
14
- /** Align with SecureYamlParser default raw YAML limit (64KB). */
15
- static MAX_YAML_SIZE = 64 * 1024;
15
+ /**
16
+ * Align with the memory save/load limit (256KB). Issue #2329: this was 64KB,
17
+ * so memories that grew past it indexed as 'unnamed' with default metadata.
18
+ */
19
+ static MAX_YAML_SIZE = MEMORY_CONSTANTS.MAX_YAML_SIZE;
16
20
  /**
17
21
  * Extract index-relevant metadata from raw YAML memory content.
18
22
  *
@@ -174,4 +178,4 @@ export class MemoryMetadataExtractor {
174
178
  return UnicodeValidator.normalize(value).normalizedContent;
175
179
  }
176
180
  }
177
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RvcmFnZS9NZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7R0FRRztBQUVILE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBRTlFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUU1QyxNQUFNLE9BQU8sdUJBQXVCO0lBQ2xDLGlFQUFpRTtJQUN6RCxNQUFNLENBQVUsYUFBYSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFFbEQ7Ozs7OztPQU1HO0lBQ0gsTUFBTSxDQUFDLGVBQWUsQ0FBQyxVQUFrQixFQUFFLFlBQW9CO1FBQzdELElBQUksQ0FBQyxVQUFVLElBQUksT0FBTyxVQUFVLEtBQUssUUFBUSxJQUFJLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDcEYsT0FBTyx1QkFBdUIsQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDNUQsQ0FBQztRQUVELE1BQU0sWUFBWSxHQUFHLHVCQUF1QixDQUFDLGtCQUFrQixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQzVFLElBQUksUUFBUSxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUM7UUFDakMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2QsMEVBQTBFO1lBQzFFLCtEQUErRDtZQUMvRCxNQUFNLFNBQVMsR0FBRyx1QkFBdUIsQ0FBQyxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUN6RSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxZQUFZLENBQUMsWUFBWSxFQUFFLENBQUM7b0JBQzlCLE1BQU0sQ0FBQyxLQUFL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RSxJQUFJLEVBQUUsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLE9BQU8sRUFBRSx1QkFBdUIsQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO1FBQ2pHLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTztnQkFDTCxZQUFZLEVBQUUsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQzthQUNyRSxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRCxnRUFBZ0U7SUFDeEQsTUFBTSxDQUFDLFlBQVksQ0FBQyxZQUFvQjtRQUM5QyxPQUFPO1lBQ0wsUUFBUSxFQUFFLFlBQVk7WUFDdEIsSUFBSSxFQUFFLFNBQVM7WUFDZixXQUFXLEVBQUUsRUFBRTtZQUNmLE9BQU8sRUFBRSxPQUFPO1lBQ2hCLE1BQU0sRUFBRSxFQUFFO1lBQ1YsSUFBSSxFQUFFLEVBQUU7WUFDUixVQUFVLEVBQUUsdUJBQXVCLENBQUMsZUFBZSxDQUFDLFlBQVksQ0FBQztTQUNsRSxDQUFDO0lBQ0osQ0FBQztJQUVPLE1BQU0sQ0FBQyxhQUFhLENBQUMsS0FBYTtRQUN4QyxPQUFPLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQztJQUM3RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBFeHRyYWN0cyBtZXRhZGF0YSBmcm9tIHB1cmUgWUFNTCBtZW1vcnkgZmlsZXMgZm9yIGxpZ2h0d2VpZ2h0IGluZGV4aW5nLlxuICpcbiAqIE1lbW9yeSBmaWxlcyBkaWZmZXIgZnJvbSBvdGhlciBlbGVtZW50czogdGhleSBhcmUgcHVyZSBZQU1MIChub3QgbWFya2Rvd25cbiAqIHdpdGggZnJvbnRtYXR0ZXIpLiBNZXRhZGF0YSBsaXZlcyB1bmRlciBhIHRvcC1sZXZlbCBgbWV0YWRhdGFgIGtleSBvclxuICogZGlyZWN0bHkgYXMgdG9wLWxldmVsIGtleXMuIFRoaXMgZXh0cmFjdG9yIHJlYWRzIHJhdyBZQU1MIGFuZCByZXR1cm5zXG4gKiB0aGUgc3Vic2V0IG9mIGZpZWxkcyBuZWVkZWQgZm9yIEVsZW1lbnRJbmRleEVudHJ5IHdpdGhvdXQgY29uc3RydWN0aW5nXG4gKiBhIGZ1bGwgTWVtb3J5IG9iamVjdC5cbiAqL1xuXG5pbXBvcnQgeyBTZWN1cmVZYW1sUGFyc2VyIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJlWWFtbFBhcnNlci5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcbmltcG9ydCB0eXBlIHsgRWxlbWVudEluZGV4RW50cnkgfSBmcm9tICcuL3R5cGVzLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5cbmV4cG9ydCBjbGFzcyBNZW1vcnlNZXRhZGF0YUV4dHJhY3RvciB7XG4gIC8qKiBBbGlnbiB3aXRoIFNlY3VyZVlhbWxQYXJzZXIgZGVmYXVsdCByYXcgWUFNTCBsaW1pdCAoNjRLQikuICovXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IE1BWF9ZQU1MX1NJWkUgPSA2NCAqIDEwMjQ7XG5cbiAgLyoqXG4gICAqIEV4dHJhY3QgaW5kZXgtcmVsZXZhbnQgbWV0YWRhdGEgZnJvbSByYXcgWUFNTCBtZW1vcnkgY29udGVudC5cbiAgICpcbiAgICogQHBhcmFtIHJhd0NvbnRlbnQgLSBGdWxsIFlBTUwgZmlsZSBjb250ZW50XG4gICAqIEBwYXJhbSByZWxhdGl2ZVBhdGggLSBQYXRoIHJlbGF0aXZlIHRvIHRoZSBtZW1vcmllcyBlbGVtZW50IGRpcmVjdG9yeVxuICAgKiBAcmV0dXJucyBQYXJ0aWFsIEVsZW1lbnRJbmRleEVudHJ5IHdpdGggZXh0cmFjdGVkIGZpZWxkc1xuICAgKi9cbiAgc3RhdGljIGV4dHJhY3RNZXRhZGF0YShyYXdDb250ZW50OiBzdHJpbmcsIHJlbGF0aXZlUGF0aDogc3RyaW5nKTogUGFydGlhbDxFbGVtZW50SW5kZXhFbnRyeT4ge1xuICAgIGlmICghcmF3Q29udGVudCB8fCB0eXBlb2YgcmF3Q29udGVudCAhPT0gJ3N0cmluZycgfHwgcmF3Q29udGVudC50cmltKCkubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IuZGVmYXVsdEVudHJ5KHJlbGF0aXZlUGF0aCk7XG4gICAgfVxuXG4gICAgY29uc3QgcHJpbWFyeVBhcnNlID0gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IudHJ5UGFyc2VZYW1sT2JqZWN0KHJhd0NvbnRlbnQpO1xuICAgIGxldCB5YW1sRGF0YSA9IHByaW1hcnlQYXJzZS5kYXRhO1xuICAgIGlmICgheWFtbERhdGEpIHtcbiAgICAgIC8vIE11bHRpLWRvY3VtZW50IHN0cmVhbXMgKGZyb250bWF0dGVyICsgY29udGVudCkgZmFpbCBzaW5nbGUtZG9jIHBhcnNpbmcuXG4gICAgICAvLyBFeHRyYWN0IGp1c3QgdGhlIGZyb250bWF0dGVyIGJsb2NrIGFuZCByZXRyeSBwYXJzaW5nIHNhZmVseS5cbiAgICAgIGNvbnN0IGZtQ29udGVudCA9IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLmV4dHJhY3RGcm9udG1hdHRlcihyYXdDb250ZW50KTtcbiAgICAgIGlmICghZm1Db250ZW50KSB7XG4gICAgICAgIGlmIChwcmltYXJ5UGFyc2UuZXJyb3JNZXNzYWdlKSB7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKCdNZW1vcnlNZXRhZGF0YUV4dHJhY3RvcjogZmFpbGVkIHRvIHBhcnNlIFlBTUwsIHJldHVybmluZyBkZWZhdWx0IG1ldGFkYXRhJywge1xuICAgICAgICAgICAgcmVsYXRpdmVQYXRoLFxuICAgICAgICAgICAgc3RhZ2U6ICdwcmltYXJ5JyxcbiAgICAgICAgICAgIGVycm9yOiBwcmltYXJ5UGFyc2UuZXJyb3JNZXNzYWdlLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5kZWZhdWx0RW50cnkocmVsYXRpdmVQYXRoKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGZhbGxiYWNrUGFyc2UgPSBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci50cnlQYXJzZVlhbWxPYmplY3QoZm1Db250ZW50KTtcbiAgICAgIHlhbWxEYXRhID0gZmFsbGJhY2tQYXJzZS5kYXRhO1xuICAgICAgaWYgKCF5YW1sRGF0YSkge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ01lbW9yeU1ldGFkYXRhRXh0cmFjdG9yOiBmYWlsZWQgdG8gcGFyc2UgWUFNTCAocHJpbWFyeSArIGZyb250bWF0dGVyIGZhbGxiYWNrKSwgcmV0dXJuaW5nIGRlZmF1bHQgbWV0YWRhdGEnLCB7XG4gICAgICAgICAgcmVsYXRpdmVQYXRoLFxuICAgICAgICAgIHByaW1hcnlFcnJvcjogcHJpbWFyeVBhcnNlLmVycm9yTWVzc2FnZSxcbiAgICAgICAgICBmYWxsYmFja0Vycm9yOiBmYWxsYmFja1BhcnNlLmVycm9yTWVzc2FnZSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5kZWZhdWx0RW50cnkocmVsYXRpdmVQYXRoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBNZW1vcnkgZmlsZXMgc3RvcmUgbWV0YWRhdGEgdW5kZXIgYSB0b3AtbGV2ZWwgYG1ldGFkYXRhYCBrZXkgb3IgZGlyZWN0bHkgYXMgdG9wLWxldmVsIGtleXNcbiAgICBjb25zdCBtZXRhZGF0YVNvdXJjZSA9IChcbiAgICAgIHlhbWxEYXRhLm1ldGFkYXRhICYmIHR5cGVvZiB5YW1sRGF0YS5tZXRhZGF0YSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoeWFtbERhdGEubWV0YWRhdGEpXG4gICAgICAgID8geWFtbERhdGEubWV0YWRhdGFcbiAgICAgICAgOiB5YW1sRGF0YVxuICAgICkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG5cbiAgICBjb25zdCBub3JtYWxpemVkTmFtZSA9IHR5cGVvZiBtZXRhZGF0YVNvdXJjZS5uYW1lID09PSAnc3RyaW5nJ1xuICAgICAgPyBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5ub3JtYWxpemVUZXh0KG1ldGFkYXRhU291cmNlLm5hbWUpXG4gICAgICA6ICcnO1xuICAgIGNvbnN0IG5hbWUgPSBub3JtYWxpemVkTmFtZS5sZW5ndGggPiAwXG4gICAgICA/IG5vcm1hbGl6ZWROYW1lXG4gICAgICA6ICd1bm5hbWVkJztcblxuICAgIGNvbnN0IGRlc2NyaXB0aW9uID0gdHlwZW9mIG1ldGFkYXRhU291cmNlLmRlc2NyaXB0aW9uID09PSAnc3RyaW5nJ1xuICAgICAgPyBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5ub3JtYWxpemVUZXh0KG1ldGFkYXRhU291cmNlLmRlc2NyaXB0aW9uKVxuICAgICAgOiAnJztcblxuICAgIGNvbnN0IG5vcm1hbGl6ZWRWZXJzaW9uID0gdHlwZW9mIG1ldGFkYXRhU291cmNlLnZlcnNpb24gPT09ICdzdHJpbmcnXG4gICAgICA/IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLm5vcm1hbGl6ZVRleHQobWV0YWRhdGFTb3VyY2UudmVyc2lvbilcbiAgICAgIDogJyc7XG4gICAgY29uc3QgdmVyc2lvbiA9IG5vcm1hbGl6ZWRWZXJzaW9uLmxlbmd0aCA+IDBcbiAgICAgID8gbm9ybWFsaXplZFZlcnNpb25cbiAgICAgIDogJzEuMC4wJztcblxuICAgIGNvbnN0IGF1dGhvciA9IHR5cGVvZiBtZXRhZGF0YVNvdXJjZS5hdXRob3IgPT09ICdzdHJpbmcnXG4gICAgICA/IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLm5vcm1hbGl6ZVRleHQobWV0YWRhdGFTb3VyY2UuYXV0aG9yKVxuICAgICAgOiAnJztcblxuICAgIGNvbnN0IHRhZ3MgPSBBcnJheS5pc0FycmF5KG1ldGFkYXRhU291cmNlLnRhZ3MpICYmIG1ldGFkYXRhU291cmNlLnRhZ3MuZXZlcnkoKHQ6IHVua25vd24pID0+IHR5cGVvZiB0ID09PSAnc3RyaW5nJylcbiAgICAgID8gKG1ldGFkYXRhU291cmNlLnRhZ3MgYXMgc3RyaW5nW10pXG4gICAgICAgIC5tYXAodGFnID0+IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLm5vcm1hbGl6ZVRleHQodGFnKSlcbiAgICAgICAgLmZpbHRlcih0YWcgPT4gdGFnLmxlbmd0aCA+IDApXG4gICAgICA6IFtdO1xuXG4gICAgY29uc3QgYXV0b0xvYWQgPSB0eXBlb2YgbWV0YWRhdGFTb3VyY2UuYXV0b0xvYWQgPT09ICdib29sZWFuJ1xuICAgICAgPyBtZXRhZGF0YVNvdXJjZS5hdXRvTG9hZFxuICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICBjb25zdCBwcmlvcml0eSA9IHR5cGVvZiBtZXRhZGF0YVNvdXJjZS5wcmlvcml0eSA9PT0gJ251bWJlcidcbiAgICAgID8gbWV0YWRhdGFTb3VyY2UucHJpb3JpdHlcbiAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgY29uc3Qgbm9ybWFsaXplZE1lbW9yeVR5cGUgPSB0eXBlb2YgbWV0YWRhdGFTb3VyY2UubWVtb3J5VHlwZSA9PT0gJ3N0cmluZydcbiAgICAgID8gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3Iubm9ybWFsaXplVGV4dChtZXRhZGF0YVNvdXJjZS5tZW1vcnlUeXBlKVxuICAgICAgOiAnJztcbiAgICBjb25zdCBtZW1vcnlUeXBlID0gbm9ybWFsaXplZE1lbW9yeVR5cGUubGVuZ3RoID4gMFxuICAgICAgPyBub3JtYWxpemVkTWVtb3J5VHlwZVxuICAgICAgOiBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5pbmZlck1lbW9yeVR5cGUocmVsYXRpdmVQYXRoKTtcblxuICAgIC8vIHRvdGFsRW50cmllczogcHJlZmVyIHN0YXRzLnRvdGFsRW50cmllcywgZmFsbCBiYWNrIHRvIGVudHJpZXMgYXJyYXkgbGVuZ3RoXG4gICAgbGV0IHRvdGFsRW50cmllczogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICAgIGNvbnN0IHN0YXRzID0geWFtbERhdGEuc3RhdHMgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQ7XG4gICAgaWYgKHN0YXRzICYmIHR5cGVvZiBzdGF0cyA9PT0gJ29iamVjdCcgJiYgdHlwZW9mIHN0YXRzLnRvdGFsRW50cmllcyA9PT0gJ251bWJlcicpIHtcbiAgICAgIHRvdGFsRW50cmllcyA9IHN0YXRzLnRvdGFsRW50cmllcztcbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoeWFtbERhdGEuZW50cmllcykpIHtcbiAgICAgIHRvdGFsRW50cmllcyA9IHlhbWxEYXRhLmVudHJpZXMubGVuZ3RoO1xuICAgIH1cblxuICAgIGNvbnN0IGVudHJ5OiBQYXJ0aWFsPEVsZW1lbnRJbmRleEVudHJ5PiA9IHtcbiAgICAgIGZpbGVQYXRoOiByZWxhdGl2ZVBhdGgsXG4gICAgICBuYW1lLFxuICAgICAgZGVzY3JpcHRpb24sXG4gICAgICB2ZXJzaW9uLFxuICAgICAgYXV0aG9yLFxuICAgICAgdGFncyxcbiAgICAgIG1lbW9yeVR5cGUsXG4gICAgfTtcblxuICAgIGlmIChhdXRvTG9hZCAhPT0gdW5kZWZpbmVkKSBlbnRyeS5hdXRvTG9hZCA9IGF1dG9Mb2FkO1xuICAgIGlmIChwcmlvcml0eSAhPT0gdW5kZWZpbmVkKSBlbnRyeS5wcmlvcml0eSA9IHByaW9yaXR5O1xuICAgIGlmICh0b3RhbEVudHJpZXMgIT09IHVuZGVmaW5lZCkgZW50cnkudG90YWxFbnRyaWVzID0gdG90YWxFbnRyaWVzO1xuXG4gICAgcmV0dXJuIGVudHJ5O1xuICB9XG5cbiAgLyoqXG4gICAqIEluZmVyIHRoZSBtZW1vcnkgdHlwZSBmcm9tIHRoZSBmaWxlJ3MgcmVsYXRpdmUgcGF0aC5cbiAgICpcbiAgICogQHBhcmFtIHJlbGF0aXZlUGF0aCAtIFBhdGggcmVsYXRpdmUgdG8gdGhlIG1lbW9yaWVzIGRpcmVjdG9yeVxuICAgKiBAcmV0dXJucyAnc3lzdGVtJyB8ICdhZGFwdGVyJyB8ICd1c2VyJ1xuICAgKi9cbiAgc3RhdGljIGluZmVyTWVtb3J5VHlwZShyZWxhdGl2ZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgLy8gTm9ybWFsaXplIHNlcGFyYXRvcnMgdG8gZm9yd2FyZCBzbGFzaCBmb3IgY29uc2lzdGVudCBtYXRjaGluZ1xuICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSByZWxhdGl2ZVBhdGgucmVwbGFjZSgvXFxcXC9nLCAnLycpO1xuXG4gICAgaWYgKG5vcm1hbGl6ZWQuc3RhcnRzV2l0aCgnc3lzdGVtLycpKSByZXR1cm4gJ3N5c3RlbSc7XG4gICAgaWYgKG5vcm1hbGl6ZWQuc3RhcnRzV2l0aCgnYWRhcHRlcnMvJykpIHJldHVybiAnYWRhcHRlcic7XG4gICAgcmV0dXJuICd1c2VyJztcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0IFlBTUwgY29udGVudCBiZXR3ZWVuIC0tLSBmcm9udG1hdHRlciBtYXJrZXJzLlxuICAgKiBSZXR1cm5zIG51bGwgaWYgbm8gdmFsaWQgZnJvbnRtYXR0ZXIgYmxvY2sgZm91bmQuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBleHRyYWN0RnJvbnRtYXR0ZXIocmF3Q29udGVudDogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgY29uc3QgdHJpbW1lZCA9IHJhd0NvbnRlbnQudHJpbSgpO1xuICAgIGlmICghdHJpbW1lZC5zdGFydHNXaXRoKCctLS0nKSkgcmV0dXJuIG51bGw7XG5cbiAgICBjb25zdCBlbmRJbmRleCA9IHRyaW1tZWQuaW5kZXhPZignXFxuLS0tJywgMyk7XG4gICAgaWYgKGVuZEluZGV4ID09PSAtMSkgcmV0dXJuIG51bGw7XG5cbiAgICByZXR1cm4gdHJpbW1lZC5zdWJzdHJpbmcoMywgZW5kSW5kZXgpLnRyaW0oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQYXJzZSByYXcgWUFNTCB1c2luZyB0aGUgY2VudHJhbGl6ZWQgc2VjdXJlIHBhcnNlci5cbiAgICogUmV0dXJucyBwYXJzZSBkaWFnbm9zdGljcyBzbyBjYWxsZXJzIGNhbiBmYWlsIGNsb3NlZCB3aGlsZSBwcmVzZXJ2aW5nIGVycm9yIGNvbnRleHQuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyB0cnlQYXJzZVlhbWxPYmplY3QoY29udGVudDogc3RyaW5nKTogeyBkYXRhPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47IGVycm9yTWVzc2FnZT86IHN0cmluZyB9IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHsgZGF0YTogU2VjdXJlWWFtbFBhcnNlci5wYXJzZVJhd1lhbWwoY29udGVudCwgTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IuTUFYX1lBTUxfU0laRSkgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvciksXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKiBSZXR1cm4gYSBtaW5pbWFsIGRlZmF1bHQgZW50cnkgZm9yIGVtcHR5L2NvcnJ1cHQgY29udGVudC4gKi9cbiAgcHJpdmF0ZSBzdGF0aWMgZGVmYXVsdEVudHJ5KHJlbGF0aXZlUGF0aDogc3RyaW5nKTogUGFydGlhbDxFbGVtZW50SW5kZXhFbnRyeT4ge1xuICAgIHJldHVybiB7XG4gICAgICBmaWxlUGF0aDogcmVsYXRpdmVQYXRoLFxuICAgICAgbmFtZTogJ3VubmFtZWQnLFxuICAgICAgZGVzY3JpcHRpb246ICcnLFxuICAgICAgdmVyc2lvbjogJzEuMC4wJyxcbiAgICAgIGF1dGhvcjogJycsXG4gICAgICB0YWdzOiBbXSxcbiAgICAgIG1lbW9yeVR5cGU6IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLmluZmVyTWVtb3J5VHlwZShyZWxhdGl2ZVBhdGgpLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBub3JtYWxpemVUZXh0KHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZSh2YWx1ZSkubm9ybWFsaXplZENvbnRlbnQ7XG4gIH1cbn1cbiJdfQ==
181
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RvcmFnZS9NZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7R0FRRztBQUVILE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBQzlFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBRXJFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUU1QyxNQUFNLE9BQU8sdUJBQXVCO0lBQ2xDOzs7T0FHRztJQUNLLE1BQU0sQ0FBVSxhQUFhLEdBQUcsZ0JBQWdCLENBQUMsYUFBYSxDQUFDO0lBRXZFOzs7Ozs7T0FNRztJQUNILE1BQU0sQ0FBQyxlQUFlLENBQUMsVUFBa0IsRUFBRSxZQUFvQjtRQUM3RCxJQUFJLENBQUMsVUFBVSxJQUFJLE9BQU8sVUFBVSxLQUFLLFFBQVEsSUFBSSxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3BGLE9BQU8sdUJBQXVCLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzVELENBQUM7UUFFRCxNQUFNLFlBQVksR0FBRyx1QkFBdUIsQ0FBQyxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUM1RSxJQUFJLFFBQVEsR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNkLDBFQUEwRTtZQUMxRSwrREFBK0Q7WUFDL0QsTUFBTSxTQUFTLEdBQUcsdUJBQXVCLENBQUMsa0JBQWtCLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDekUsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNmLElBQUks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a0JBQWtCLENBQUMsT0FBZTtRQUMvQyxJQUFJLENBQUM7WUFDSCxPQUFPLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsdUJBQXVCLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztRQUNqRyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU87Z0JBQ0wsWUFBWSxFQUFFLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUM7YUFDckUsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQsZ0VBQWdFO0lBQ3hELE1BQU0sQ0FBQyxZQUFZLENBQUMsWUFBb0I7UUFDOUMsT0FBTztZQUNMLFFBQVEsRUFBRSxZQUFZO1lBQ3RCLElBQUksRUFBRSxTQUFTO1lBQ2YsV0FBVyxFQUFFLEVBQUU7WUFDZixPQUFPLEVBQUUsT0FBTztZQUNoQixNQUFNLEVBQUUsRUFBRTtZQUNWLElBQUksRUFBRSxFQUFFO1lBQ1IsVUFBVSxFQUFFLHVCQUF1QixDQUFDLGVBQWUsQ0FBQyxZQUFZLENBQUM7U0FDbEUsQ0FBQztJQUNKLENBQUM7SUFFTyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQWE7UUFDeEMsT0FBTyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsaUJBQWlCLENBQUM7SUFDN0QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRXh0cmFjdHMgbWV0YWRhdGEgZnJvbSBwdXJlIFlBTUwgbWVtb3J5IGZpbGVzIGZvciBsaWdodHdlaWdodCBpbmRleGluZy5cbiAqXG4gKiBNZW1vcnkgZmlsZXMgZGlmZmVyIGZyb20gb3RoZXIgZWxlbWVudHM6IHRoZXkgYXJlIHB1cmUgWUFNTCAobm90IG1hcmtkb3duXG4gKiB3aXRoIGZyb250bWF0dGVyKS4gTWV0YWRhdGEgbGl2ZXMgdW5kZXIgYSB0b3AtbGV2ZWwgYG1ldGFkYXRhYCBrZXkgb3JcbiAqIGRpcmVjdGx5IGFzIHRvcC1sZXZlbCBrZXlzLiBUaGlzIGV4dHJhY3RvciByZWFkcyByYXcgWUFNTCBhbmQgcmV0dXJuc1xuICogdGhlIHN1YnNldCBvZiBmaWVsZHMgbmVlZGVkIGZvciBFbGVtZW50SW5kZXhFbnRyeSB3aXRob3V0IGNvbnN0cnVjdGluZ1xuICogYSBmdWxsIE1lbW9yeSBvYmplY3QuXG4gKi9cblxuaW1wb3J0IHsgU2VjdXJlWWFtbFBhcnNlciB9IGZyb20gJy4uL3NlY3VyaXR5L3NlY3VyZVlhbWxQYXJzZXIuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBNRU1PUllfQ09OU1RBTlRTIH0gZnJvbSAnLi4vZWxlbWVudHMvbWVtb3JpZXMvY29uc3RhbnRzLmpzJztcbmltcG9ydCB0eXBlIHsgRWxlbWVudEluZGV4RW50cnkgfSBmcm9tICcuL3R5cGVzLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5cbmV4cG9ydCBjbGFzcyBNZW1vcnlNZXRhZGF0YUV4dHJhY3RvciB7XG4gIC8qKlxuICAgKiBBbGlnbiB3aXRoIHRoZSBtZW1vcnkgc2F2ZS9sb2FkIGxpbWl0ICgyNTZLQikuIElzc3VlICMyMzI5OiB0aGlzIHdhcyA2NEtCLFxuICAgKiBzbyBtZW1vcmllcyB0aGF0IGdyZXcgcGFzdCBpdCBpbmRleGVkIGFzICd1bm5hbWVkJyB3aXRoIGRlZmF1bHQgbWV0YWRhdGEuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBNQVhfWUFNTF9TSVpFID0gTUVNT1JZX0NPTlNUQU5UUy5NQVhfWUFNTF9TSVpFO1xuXG4gIC8qKlxuICAgKiBFeHRyYWN0IGluZGV4LXJlbGV2YW50IG1ldGFkYXRhIGZyb20gcmF3IFlBTUwgbWVtb3J5IGNvbnRlbnQuXG4gICAqXG4gICAqIEBwYXJhbSByYXdDb250ZW50IC0gRnVsbCBZQU1MIGZpbGUgY29udGVudFxuICAgKiBAcGFyYW0gcmVsYXRpdmVQYXRoIC0gUGF0aCByZWxhdGl2ZSB0byB0aGUgbWVtb3JpZXMgZWxlbWVudCBkaXJlY3RvcnlcbiAgICogQHJldHVybnMgUGFydGlhbCBFbGVtZW50SW5kZXhFbnRyeSB3aXRoIGV4dHJhY3RlZCBmaWVsZHNcbiAgICovXG4gIHN0YXRpYyBleHRyYWN0TWV0YWRhdGEocmF3Q29udGVudDogc3RyaW5nLCByZWxhdGl2ZVBhdGg6IHN0cmluZyk6IFBhcnRpYWw8RWxlbWVudEluZGV4RW50cnk+IHtcbiAgICBpZiAoIXJhd0NvbnRlbnQgfHwgdHlwZW9mIHJhd0NvbnRlbnQgIT09ICdzdHJpbmcnIHx8IHJhd0NvbnRlbnQudHJpbSgpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLmRlZmF1bHRFbnRyeShyZWxhdGl2ZVBhdGgpO1xuICAgIH1cblxuICAgIGNvbnN0IHByaW1hcnlQYXJzZSA9IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLnRyeVBhcnNlWWFtbE9iamVjdChyYXdDb250ZW50KTtcbiAgICBsZXQgeWFtbERhdGEgPSBwcmltYXJ5UGFyc2UuZGF0YTtcbiAgICBpZiAoIXlhbWxEYXRhKSB7XG4gICAgICAvLyBNdWx0aS1kb2N1bWVudCBzdHJlYW1zIChmcm9udG1hdHRlciArIGNvbnRlbnQpIGZhaWwgc2luZ2xlLWRvYyBwYXJzaW5nLlxuICAgICAgLy8gRXh0cmFjdCBqdXN0IHRoZSBmcm9udG1hdHRlciBibG9jayBhbmQgcmV0cnkgcGFyc2luZyBzYWZlbHkuXG4gICAgICBjb25zdCBmbUNvbnRlbnQgPSBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5leHRyYWN0RnJvbnRtYXR0ZXIocmF3Q29udGVudCk7XG4gICAgICBpZiAoIWZtQ29udGVudCkge1xuICAgICAgICBpZiAocHJpbWFyeVBhcnNlLmVycm9yTWVzc2FnZSkge1xuICAgICAgICAgIGxvZ2dlci5kZWJ1ZygnTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3I6IGZhaWxlZCB0byBwYXJzZSBZQU1MLCByZXR1cm5pbmcgZGVmYXVsdCBtZXRhZGF0YScsIHtcbiAgICAgICAgICAgIHJlbGF0aXZlUGF0aCxcbiAgICAgICAgICAgIHN0YWdlOiAncHJpbWFyeScsXG4gICAgICAgICAgICBlcnJvcjogcHJpbWFyeVBhcnNlLmVycm9yTWVzc2FnZSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IuZGVmYXVsdEVudHJ5KHJlbGF0aXZlUGF0aCk7XG4gICAgICB9XG4gICAgICBjb25zdCBmYWxsYmFja1BhcnNlID0gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IudHJ5UGFyc2VZYW1sT2JqZWN0KGZtQ29udGVudCk7XG4gICAgICB5YW1sRGF0YSA9IGZhbGxiYWNrUGFyc2UuZGF0YTtcbiAgICAgIGlmICgheWFtbERhdGEpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdNZW1vcnlNZXRhZGF0YUV4dHJhY3RvcjogZmFpbGVkIHRvIHBhcnNlIFlBTUwgKHByaW1hcnkgKyBmcm9udG1hdHRlciBmYWxsYmFjayksIHJldHVybmluZyBkZWZhdWx0IG1ldGFkYXRhJywge1xuICAgICAgICAgIHJlbGF0aXZlUGF0aCxcbiAgICAgICAgICBwcmltYXJ5RXJyb3I6IHByaW1hcnlQYXJzZS5lcnJvck1lc3NhZ2UsXG4gICAgICAgICAgZmFsbGJhY2tFcnJvcjogZmFsbGJhY2tQYXJzZS5lcnJvck1lc3NhZ2UsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IuZGVmYXVsdEVudHJ5KHJlbGF0aXZlUGF0aCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gTWVtb3J5IGZpbGVzIHN0b3JlIG1ldGFkYXRhIHVuZGVyIGEgdG9wLWxldmVsIGBtZXRhZGF0YWAga2V5IG9yIGRpcmVjdGx5IGFzIHRvcC1sZXZlbCBrZXlzXG4gICAgY29uc3QgbWV0YWRhdGFTb3VyY2UgPSAoXG4gICAgICB5YW1sRGF0YS5tZXRhZGF0YSAmJiB0eXBlb2YgeWFtbERhdGEubWV0YWRhdGEgPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KHlhbWxEYXRhLm1ldGFkYXRhKVxuICAgICAgICA/IHlhbWxEYXRhLm1ldGFkYXRhXG4gICAgICAgIDogeWFtbERhdGFcbiAgICApIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuXG4gICAgY29uc3Qgbm9ybWFsaXplZE5hbWUgPSB0eXBlb2YgbWV0YWRhdGFTb3VyY2UubmFtZSA9PT0gJ3N0cmluZydcbiAgICAgID8gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3Iubm9ybWFsaXplVGV4dChtZXRhZGF0YVNvdXJjZS5uYW1lKVxuICAgICAgOiAnJztcbiAgICBjb25zdCBuYW1lID0gbm9ybWFsaXplZE5hbWUubGVuZ3RoID4gMFxuICAgICAgPyBub3JtYWxpemVkTmFtZVxuICAgICAgOiAndW5uYW1lZCc7XG5cbiAgICBjb25zdCBkZXNjcmlwdGlvbiA9IHR5cGVvZiBtZXRhZGF0YVNvdXJjZS5kZXNjcmlwdGlvbiA9PT0gJ3N0cmluZydcbiAgICAgID8gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3Iubm9ybWFsaXplVGV4dChtZXRhZGF0YVNvdXJjZS5kZXNjcmlwdGlvbilcbiAgICAgIDogJyc7XG5cbiAgICBjb25zdCBub3JtYWxpemVkVmVyc2lvbiA9IHR5cGVvZiBtZXRhZGF0YVNvdXJjZS52ZXJzaW9uID09PSAnc3RyaW5nJ1xuICAgICAgPyBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5ub3JtYWxpemVUZXh0KG1ldGFkYXRhU291cmNlLnZlcnNpb24pXG4gICAgICA6ICcnO1xuICAgIGNvbnN0IHZlcnNpb24gPSBub3JtYWxpemVkVmVyc2lvbi5sZW5ndGggPiAwXG4gICAgICA/IG5vcm1hbGl6ZWRWZXJzaW9uXG4gICAgICA6ICcxLjAuMCc7XG5cbiAgICBjb25zdCBhdXRob3IgPSB0eXBlb2YgbWV0YWRhdGFTb3VyY2UuYXV0aG9yID09PSAnc3RyaW5nJ1xuICAgICAgPyBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5ub3JtYWxpemVUZXh0KG1ldGFkYXRhU291cmNlLmF1dGhvcilcbiAgICAgIDogJyc7XG5cbiAgICBjb25zdCB0YWdzID0gQXJyYXkuaXNBcnJheShtZXRhZGF0YVNvdXJjZS50YWdzKSAmJiBtZXRhZGF0YVNvdXJjZS50YWdzLmV2ZXJ5KCh0OiB1bmtub3duKSA9PiB0eXBlb2YgdCA9PT0gJ3N0cmluZycpXG4gICAgICA/IChtZXRhZGF0YVNvdXJjZS50YWdzIGFzIHN0cmluZ1tdKVxuICAgICAgICAubWFwKHRhZyA9PiBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5ub3JtYWxpemVUZXh0KHRhZykpXG4gICAgICAgIC5maWx0ZXIodGFnID0+IHRhZy5sZW5ndGggPiAwKVxuICAgICAgOiBbXTtcblxuICAgIGNvbnN0IGF1dG9Mb2FkID0gdHlwZW9mIG1ldGFkYXRhU291cmNlLmF1dG9Mb2FkID09PSAnYm9vbGVhbidcbiAgICAgID8gbWV0YWRhdGFTb3VyY2UuYXV0b0xvYWRcbiAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgY29uc3QgcHJpb3JpdHkgPSB0eXBlb2YgbWV0YWRhdGFTb3VyY2UucHJpb3JpdHkgPT09ICdudW1iZXInXG4gICAgICA/IG1ldGFkYXRhU291cmNlLnByaW9yaXR5XG4gICAgICA6IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IG5vcm1hbGl6ZWRNZW1vcnlUeXBlID0gdHlwZW9mIG1ldGFkYXRhU291cmNlLm1lbW9yeVR5cGUgPT09ICdzdHJpbmcnXG4gICAgICA/IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLm5vcm1hbGl6ZVRleHQobWV0YWRhdGFTb3VyY2UubWVtb3J5VHlwZSlcbiAgICAgIDogJyc7XG4gICAgY29uc3QgbWVtb3J5VHlwZSA9IG5vcm1hbGl6ZWRNZW1vcnlUeXBlLmxlbmd0aCA+IDBcbiAgICAgID8gbm9ybWFsaXplZE1lbW9yeVR5cGVcbiAgICAgIDogTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IuaW5mZXJNZW1vcnlUeXBlKHJlbGF0aXZlUGF0aCk7XG5cbiAgICAvLyB0b3RhbEVudHJpZXM6IHByZWZlciBzdGF0cy50b3RhbEVudHJpZXMsIGZhbGwgYmFjayB0byBlbnRyaWVzIGFycmF5IGxlbmd0aFxuICAgIGxldCB0b3RhbEVudHJpZXM6IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCBzdGF0cyA9IHlhbWxEYXRhLnN0YXRzIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkO1xuICAgIGlmIChzdGF0cyAmJiB0eXBlb2Ygc3RhdHMgPT09ICdvYmplY3QnICYmIHR5cGVvZiBzdGF0cy50b3RhbEVudHJpZXMgPT09ICdudW1iZXInKSB7XG4gICAgICB0b3RhbEVudHJpZXMgPSBzdGF0cy50b3RhbEVudHJpZXM7XG4gICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KHlhbWxEYXRhLmVudHJpZXMpKSB7XG4gICAgICB0b3RhbEVudHJpZXMgPSB5YW1sRGF0YS5lbnRyaWVzLmxlbmd0aDtcbiAgICB9XG5cbiAgICBjb25zdCBlbnRyeTogUGFydGlhbDxFbGVtZW50SW5kZXhFbnRyeT4gPSB7XG4gICAgICBmaWxlUGF0aDogcmVsYXRpdmVQYXRoLFxuICAgICAgbmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uLFxuICAgICAgdmVyc2lvbixcbiAgICAgIGF1dGhvcixcbiAgICAgIHRhZ3MsXG4gICAgICBtZW1vcnlUeXBlLFxuICAgIH07XG5cbiAgICBpZiAoYXV0b0xvYWQgIT09IHVuZGVmaW5lZCkgZW50cnkuYXV0b0xvYWQgPSBhdXRvTG9hZDtcbiAgICBpZiAocHJpb3JpdHkgIT09IHVuZGVmaW5lZCkgZW50cnkucHJpb3JpdHkgPSBwcmlvcml0eTtcbiAgICBpZiAodG90YWxFbnRyaWVzICE9PSB1bmRlZmluZWQpIGVudHJ5LnRvdGFsRW50cmllcyA9IHRvdGFsRW50cmllcztcblxuICAgIHJldHVybiBlbnRyeTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmZlciB0aGUgbWVtb3J5IHR5cGUgZnJvbSB0aGUgZmlsZSdzIHJlbGF0aXZlIHBhdGguXG4gICAqXG4gICAqIEBwYXJhbSByZWxhdGl2ZVBhdGggLSBQYXRoIHJlbGF0aXZlIHRvIHRoZSBtZW1vcmllcyBkaXJlY3RvcnlcbiAgICogQHJldHVybnMgJ3N5c3RlbScgfCAnYWRhcHRlcicgfCAndXNlcidcbiAgICovXG4gIHN0YXRpYyBpbmZlck1lbW9yeVR5cGUocmVsYXRpdmVQYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIC8vIE5vcm1hbGl6ZSBzZXBhcmF0b3JzIHRvIGZvcndhcmQgc2xhc2ggZm9yIGNvbnNpc3RlbnQgbWF0Y2hpbmdcbiAgICBjb25zdCBub3JtYWxpemVkID0gcmVsYXRpdmVQYXRoLnJlcGxhY2UoL1xcXFwvZywgJy8nKTtcblxuICAgIGlmIChub3JtYWxpemVkLnN0YXJ0c1dpdGgoJ3N5c3RlbS8nKSkgcmV0dXJuICdzeXN0ZW0nO1xuICAgIGlmIChub3JtYWxpemVkLnN0YXJ0c1dpdGgoJ2FkYXB0ZXJzLycpKSByZXR1cm4gJ2FkYXB0ZXInO1xuICAgIHJldHVybiAndXNlcic7XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdCBZQU1MIGNvbnRlbnQgYmV0d2VlbiAtLS0gZnJvbnRtYXR0ZXIgbWFya2Vycy5cbiAgICogUmV0dXJucyBudWxsIGlmIG5vIHZhbGlkIGZyb250bWF0dGVyIGJsb2NrIGZvdW5kLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgZXh0cmFjdEZyb250bWF0dGVyKHJhd0NvbnRlbnQ6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICAgIGNvbnN0IHRyaW1tZWQgPSByYXdDb250ZW50LnRyaW0oKTtcbiAgICBpZiAoIXRyaW1tZWQuc3RhcnRzV2l0aCgnLS0tJykpIHJldHVybiBudWxsO1xuXG4gICAgY29uc3QgZW5kSW5kZXggPSB0cmltbWVkLmluZGV4T2YoJ1xcbi0tLScsIDMpO1xuICAgIGlmIChlbmRJbmRleCA9PT0gLTEpIHJldHVybiBudWxsO1xuXG4gICAgcmV0dXJuIHRyaW1tZWQuc3Vic3RyaW5nKDMsIGVuZEluZGV4KS50cmltKCk7XG4gIH1cblxuICAvKipcbiAgICogUGFyc2UgcmF3IFlBTUwgdXNpbmcgdGhlIGNlbnRyYWxpemVkIHNlY3VyZSBwYXJzZXIuXG4gICAqIFJldHVybnMgcGFyc2UgZGlhZ25vc3RpY3Mgc28gY2FsbGVycyBjYW4gZmFpbCBjbG9zZWQgd2hpbGUgcHJlc2VydmluZyBlcnJvciBjb250ZXh0LlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgdHJ5UGFyc2VZYW1sT2JqZWN0KGNvbnRlbnQ6IHN0cmluZyk6IHsgZGF0YT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+OyBlcnJvck1lc3NhZ2U/OiBzdHJpbmcgfSB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiB7IGRhdGE6IFNlY3VyZVlhbWxQYXJzZXIucGFyc2VSYXdZYW1sKGNvbnRlbnQsIE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLk1BWF9ZQU1MX1NJWkUpIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGVycm9yTWVzc2FnZTogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICAvKiogUmV0dXJuIGEgbWluaW1hbCBkZWZhdWx0IGVudHJ5IGZvciBlbXB0eS9jb3JydXB0IGNvbnRlbnQuICovXG4gIHByaXZhdGUgc3RhdGljIGRlZmF1bHRFbnRyeShyZWxhdGl2ZVBhdGg6IHN0cmluZyk6IFBhcnRpYWw8RWxlbWVudEluZGV4RW50cnk+IHtcbiAgICByZXR1cm4ge1xuICAgICAgZmlsZVBhdGg6IHJlbGF0aXZlUGF0aCxcbiAgICAgIG5hbWU6ICd1bm5hbWVkJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnJyxcbiAgICAgIHZlcnNpb246ICcxLjAuMCcsXG4gICAgICBhdXRob3I6ICcnLFxuICAgICAgdGFnczogW10sXG4gICAgICBtZW1vcnlUeXBlOiBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5pbmZlck1lbW9yeVR5cGUocmVsYXRpdmVQYXRoKSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgbm9ybWFsaXplVGV4dCh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUodmFsdWUpLm5vcm1hbGl6ZWRDb250ZW50O1xuICB9XG59XG4iXX0=
package/oauth-helper.mjs CHANGED
@@ -13,20 +13,38 @@
13
13
  * between tool calls, breaking background OAuth polling.
14
14
  */
15
15
 
16
- import { fileURLToPath } from 'url';
17
16
  import { dirname, join } from 'path';
18
17
  import fs from 'fs/promises';
19
18
  import fsSync from 'fs';
20
19
  import { homedir } from 'os';
21
20
 
22
- // Get the directory of this script
23
- const __filename = fileURLToPath(import.meta.url);
24
- const __dirname = dirname(__filename);
25
-
26
21
  // Constants
27
22
  const DEFAULT_POLL_INTERVAL = 5;
28
23
  const DEFAULT_EXPIRES_IN = 900; // 15 minutes
29
24
  const MAX_TOKEN_SIZE = 10000; // Maximum reasonable token size
25
+ const DOLLHOUSE_HOME_DIR = process.env.DOLLHOUSE_HOME_DIR || homedir();
26
+ const AUTH_DIR = join(DOLLHOUSE_HOME_DIR, '.dollhouse', '.auth');
27
+ const PID_FILE = join(AUTH_DIR, 'oauth-helper.pid');
28
+ const STATE_FILE = join(AUTH_DIR, 'oauth-helper-state.json');
29
+ const RESULT_FILE = join(AUTH_DIR, 'oauth-helper-result.json');
30
+ const LOG_FILE = join(DOLLHOUSE_HOME_DIR, '.dollhouse', 'oauth-helper.log');
31
+ const FLOW_ID = process.env.DOLLHOUSE_OAUTH_HELPER_FLOW_ID || '';
32
+ const TOKEN_URL = process.env.DOLLHOUSE_OAUTH_TOKEN_URL || 'https://github.com/login/oauth/access_token';
33
+ const LOG_ENABLED = process.env.DOLLHOUSE_OAUTH_DEBUG === 'true';
34
+
35
+ const RESULT_MESSAGES = {
36
+ success: 'OAuth helper completed successfully.',
37
+ expired_token: 'Device code expired before authorization completed.',
38
+ access_denied: 'User denied the GitHub authorization request.',
39
+ timeout: 'Authorization timed out before the user completed GitHub authorization.',
40
+ token_storage_failed: 'OAuth token could not be stored securely.',
41
+ network_failure: 'Too many network errors while contacting the OAuth token endpoint.',
42
+ fatal_error: 'OAuth helper stopped after an unrecoverable error.',
43
+ interrupted: 'OAuth helper was interrupted before authentication completed.',
44
+ unknown_response: 'OAuth token endpoint returned an unrecognized response.',
45
+ };
46
+
47
+ const ALLOWED_RESULT_ERROR_CODES = new Set(Object.keys(RESULT_MESSAGES));
30
48
 
31
49
  // Parse command line arguments
32
50
  const args = process.argv.slice(2);
@@ -36,8 +54,8 @@ if (args.length < 4) {
36
54
  }
37
55
 
38
56
  const [deviceCode, intervalStr, expiresInStr, clientId] = args;
39
- const pollInterval = parseInt(intervalStr, 10) || DEFAULT_POLL_INTERVAL;
40
- const expiresIn = parseInt(expiresInStr, 10) || DEFAULT_EXPIRES_IN;
57
+ const pollIntervalSeconds = Number.parseInt(intervalStr, 10) || DEFAULT_POLL_INTERVAL;
58
+ const expiresIn = Number.parseInt(expiresInStr, 10) || DEFAULT_EXPIRES_IN;
41
59
 
42
60
  // Validate client ID is provided (no hardcoded fallback)
43
61
  if (!clientId || clientId === 'undefined') {
@@ -50,10 +68,6 @@ if (!clientId || clientId === 'undefined') {
50
68
  process.exit(1);
51
69
  }
52
70
 
53
- // Log file for debugging (optional, can be disabled in production)
54
- const LOG_FILE = join(homedir(), '.dollhouse', 'oauth-helper.log');
55
- const LOG_ENABLED = process.env.DOLLHOUSE_OAUTH_DEBUG === 'true';
56
-
57
71
  async function log(message) {
58
72
  if (!LOG_ENABLED) return;
59
73
 
@@ -86,13 +100,18 @@ async function log(message) {
86
100
  }
87
101
  }
88
102
 
103
+ function sanitizeDiagnostic(value) {
104
+ return String(value ?? '')
105
+ .replace(/\bgithub_pat_\w+\b/g, '[REDACTED_GITHUB_TOKEN]')
106
+ .replace(/\bgh[a-z]_\w+\b/gi, '[REDACTED_GITHUB_TOKEN]')
107
+ .replaceAll(deviceCode, '[REDACTED_DEVICE_CODE]');
108
+ }
109
+
89
110
  async function sleep(ms) {
90
111
  return new Promise(resolve => setTimeout(resolve, ms));
91
112
  }
92
113
 
93
114
  async function pollGitHub(deviceCode, clientId) {
94
- const TOKEN_URL = 'https://github.com/login/oauth/access_token';
95
-
96
115
  try {
97
116
  const response = await fetch(TOKEN_URL, {
98
117
  method: 'POST',
@@ -124,74 +143,187 @@ async function storeToken(token) {
124
143
 
125
144
  try {
126
145
  // Import the compiled TokenManager
127
- const { TokenManager } = await import('./dist/security/tokenManager.js');
146
+ const { TokenManager } = await import(new URL('./dist/security/tokenManager.js', import.meta.url).href);
128
147
 
129
- // Store the token using the secure storage mechanism
130
- await TokenManager.storeGitHubToken(token);
148
+ // Store the token using the secure file-backed storage mechanism.
149
+ const tokenManager = new TokenManager(createHelperFileOperations());
150
+ await tokenManager.storeGitHubToken(token);
131
151
  await log('Token stored successfully using TokenManager');
132
152
  return true;
133
- } catch {
134
- await log('Failed to store token using TokenManager');
135
-
136
- // Fallback: Write to a temporary file for the MCP server to pick up
137
- try {
138
- const tempTokenFile = join(homedir(), '.dollhouse', '.auth', 'pending_token.txt');
139
- const tempDir = dirname(tempTokenFile);
140
-
141
- // Create directory with secure permissions
142
- await fs.mkdir(tempDir, { recursive: true, mode: 0o700 });
143
-
144
- // Verify directory permissions
145
- const dirStats = await fs.stat(tempDir);
146
- const dirMode = dirStats.mode & parseInt('777', 8);
147
- if (dirMode !== parseInt('700', 8)) {
148
- await fs.chmod(tempDir, 0o700);
153
+ } catch (error) {
154
+ await log(`Failed to store token using TokenManager: ${sanitizeDiagnostic(error instanceof Error ? error.message : 'Unknown error')}`);
155
+ throw error;
156
+ }
157
+ }
158
+
159
+ function createHelperFileOperations() {
160
+ // Paths are fixed by AUTH_DIR constants, so this standalone helper only needs
161
+ // the small FileOperations surface TokenManager uses for secure storage.
162
+ return {
163
+ async createDirectory(directoryPath) {
164
+ await fs.mkdir(directoryPath, { recursive: true });
165
+ },
166
+ async readFile(filePath) {
167
+ return fs.readFile(filePath, 'utf8');
168
+ },
169
+ async writeFile(filePath, content) {
170
+ await fs.writeFile(filePath, content, { encoding: 'utf8' });
171
+ },
172
+ async deleteFile(filePath) {
173
+ await fs.unlink(filePath);
174
+ },
175
+ async chmod(filePath, mode) {
176
+ await fs.chmod(filePath, mode);
177
+ },
178
+ async exists(filePath) {
179
+ try {
180
+ await fs.access(filePath);
181
+ return true;
182
+ } catch {
183
+ return false;
149
184
  }
150
-
151
- // Write token with secure permissions
152
- await fs.writeFile(tempTokenFile, token, { mode: 0o600 });
153
-
154
- // Verify file permissions
155
- await fs.chmod(tempTokenFile, 0o600);
156
-
157
- await log('Token written to fallback file with secure permissions');
158
- return true;
159
- } catch (fallbackError) {
160
- await log('Fallback storage also failed');
161
- throw fallbackError;
162
185
  }
163
- }
186
+ };
164
187
  }
165
188
 
166
189
  function cleanupPidFileSync() {
167
190
  try {
168
- const pidFile = join(homedir(), '.dollhouse', '.auth', 'oauth-helper.pid');
169
- if (fsSync.existsSync(pidFile)) {
170
- fsSync.unlinkSync(pidFile);
191
+ if (pidFileBelongsToThisHelperSync()) {
192
+ fsSync.unlinkSync(PID_FILE);
171
193
  }
172
- } catch (error) {
194
+ } catch {
195
+ // Ignore cleanup errors
196
+ }
197
+ }
198
+
199
+ function cleanupStateFileSync() {
200
+ try {
201
+ if (stateFileBelongsToThisHelperSync()) {
202
+ fsSync.unlinkSync(STATE_FILE);
203
+ }
204
+ } catch {
173
205
  // Ignore cleanup errors
174
206
  }
175
207
  }
176
208
 
177
209
  async function cleanupPidFile() {
178
210
  try {
179
- const pidFile = join(homedir(), '.dollhouse', '.auth', 'oauth-helper.pid');
180
- await fs.unlink(pidFile).catch(() => {});
181
- await log('PID file cleaned up');
182
- } catch (error) {
211
+ if (await pidFileBelongsToThisHelper()) {
212
+ await fs.unlink(PID_FILE).catch(() => {});
213
+ await log('PID file cleaned up');
214
+ } else {
215
+ await log('PID file belongs to another helper flow; leaving it in place');
216
+ }
217
+ } catch {
183
218
  // Ignore cleanup errors
184
219
  }
185
220
  }
186
221
 
222
+ async function cleanupStateFile() {
223
+ try {
224
+ if (await stateFileBelongsToThisHelper()) {
225
+ await fs.unlink(STATE_FILE).catch(() => {});
226
+ await log('OAuth helper state file cleaned up');
227
+ } else {
228
+ await log('OAuth helper state belongs to another flow; leaving it in place');
229
+ }
230
+ } catch {
231
+ // Ignore cleanup errors
232
+ }
233
+ }
234
+
235
+ function buildTerminalResult(status, attempts, errorCode = '') {
236
+ const safeErrorCode = ALLOWED_RESULT_ERROR_CODES.has(errorCode) ? errorCode : 'fatal_error';
237
+ const result = {
238
+ status,
239
+ attempts,
240
+ completedAt: new Date().toISOString(),
241
+ pid: process.pid
242
+ };
243
+
244
+ if (FLOW_ID) {
245
+ result.flowId = FLOW_ID;
246
+ }
247
+
248
+ if (status !== 'success') {
249
+ result.errorCode = safeErrorCode;
250
+ result.message = RESULT_MESSAGES[safeErrorCode];
251
+ }
252
+
253
+ return { result, safeErrorCode };
254
+ }
255
+
256
+ async function writeTerminalResult(status, attempts, errorCode = '') {
257
+ try {
258
+ await fs.mkdir(AUTH_DIR, { recursive: true, mode: 0o700 });
259
+ const { result, safeErrorCode } = buildTerminalResult(status, attempts, errorCode);
260
+
261
+ await fs.writeFile(RESULT_FILE, JSON.stringify(result, null, 2), { mode: 0o600 });
262
+ const resultSuffix = status === 'success' ? '' : `/${safeErrorCode}`;
263
+ await log(`Terminal result written: ${status}${resultSuffix}`);
264
+ } catch {
265
+ await log('Failed to write terminal result');
266
+ }
267
+ }
268
+
269
+ function writeTerminalResultSync(status, attempts, errorCode = '') {
270
+ try {
271
+ fsSync.mkdirSync(AUTH_DIR, { recursive: true, mode: 0o700 });
272
+ const { result } = buildTerminalResult(status, attempts, errorCode);
273
+
274
+ fsSync.writeFileSync(RESULT_FILE, JSON.stringify(result, null, 2), { mode: 0o600 });
275
+ } catch {
276
+ // Ignore cleanup/status errors during process termination
277
+ }
278
+ }
279
+
280
+ async function pidFileBelongsToThisHelper() {
281
+ if (!FLOW_ID) return true;
282
+ try {
283
+ const pid = (await fs.readFile(PID_FILE, 'utf8')).trim();
284
+ return pid === String(process.pid);
285
+ } catch {
286
+ return false;
287
+ }
288
+ }
289
+
290
+ function pidFileBelongsToThisHelperSync() {
291
+ if (!FLOW_ID) return fsSync.existsSync(PID_FILE);
292
+ try {
293
+ const pid = fsSync.readFileSync(PID_FILE, 'utf8').trim();
294
+ return pid === String(process.pid);
295
+ } catch {
296
+ return false;
297
+ }
298
+ }
299
+
300
+ async function stateFileBelongsToThisHelper() {
301
+ if (!FLOW_ID) return true;
302
+ try {
303
+ const state = JSON.parse(await fs.readFile(STATE_FILE, 'utf8'));
304
+ return state?.flowId === FLOW_ID &&
305
+ (typeof state.pid !== 'number' || state.pid === process.pid);
306
+ } catch {
307
+ return false;
308
+ }
309
+ }
310
+
311
+ function stateFileBelongsToThisHelperSync() {
312
+ if (!FLOW_ID) return fsSync.existsSync(STATE_FILE);
313
+ try {
314
+ const state = JSON.parse(fsSync.readFileSync(STATE_FILE, 'utf8'));
315
+ return state?.flowId === FLOW_ID &&
316
+ (typeof state.pid !== 'number' || state.pid === process.pid);
317
+ } catch {
318
+ return false;
319
+ }
320
+ }
321
+
187
322
  async function writePidFile() {
188
323
  try {
189
- const pidFile = join(homedir(), '.dollhouse', '.auth', 'oauth-helper.pid');
190
- const pidDir = dirname(pidFile);
191
-
192
- await fs.mkdir(pidDir, { recursive: true, mode: 0o700 });
193
- await fs.writeFile(pidFile, process.pid.toString(), { mode: 0o600 });
194
- await log(`PID file written: ${pidFile}`);
324
+ await fs.mkdir(AUTH_DIR, { recursive: true, mode: 0o700 });
325
+ await fs.writeFile(PID_FILE, process.pid.toString(), { mode: 0o600 });
326
+ await log(`PID file written: ${PID_FILE}`);
195
327
  } catch {
196
328
  await log('Failed to write PID file');
197
329
  }
@@ -200,7 +332,7 @@ async function writePidFile() {
200
332
  async function main() {
201
333
  await log(`[START] OAuth helper started - PID: ${process.pid}`);
202
334
  await log('[CONFIG] Device code received');
203
- await log(`[CONFIG] Poll interval: ${pollInterval}s, Expires in: ${expiresIn}s`);
335
+ await log(`[CONFIG] Poll interval: ${pollIntervalSeconds}s, Expires in: ${expiresIn}s`);
204
336
  await log(`[CONFIG] Node version: ${process.version}`);
205
337
  await log(`[CONFIG] Platform: ${process.platform}`);
206
338
  // Never log client ID
@@ -219,6 +351,7 @@ async function main() {
219
351
  const timeout = startTime + (expiresIn * 1000);
220
352
  let attempts = 0;
221
353
  let consecutiveErrors = 0;
354
+ let currentPollIntervalMs = pollIntervalSeconds * 1000;
222
355
  const MAX_CONSECUTIVE_ERRORS = 5;
223
356
 
224
357
  // Set up cleanup on exit - use synchronous cleanup for exit event
@@ -233,14 +366,26 @@ async function main() {
233
366
  });
234
367
 
235
368
  process.on('SIGINT', () => {
369
+ writeTerminalResultSync('failed', attempts, 'interrupted');
370
+ cleanupStateFileSync();
236
371
  cleanupPidFileSync();
237
- process.exit(0);
372
+ process.exit(1);
238
373
  });
239
374
 
240
375
  process.on('SIGTERM', () => {
376
+ writeTerminalResultSync('failed', attempts, 'interrupted');
377
+ cleanupStateFileSync();
241
378
  cleanupPidFileSync();
242
- process.exit(0);
379
+ process.exit(1);
243
380
  });
381
+
382
+ async function finish(status, errorCode, exitCode) {
383
+ clearInterval(heartbeatInterval);
384
+ await writeTerminalResult(status, attempts, errorCode);
385
+ await cleanupStateFile();
386
+ await cleanupPidFile();
387
+ process.exit(exitCode);
388
+ }
244
389
 
245
390
  while (Date.now() < timeout) {
246
391
  attempts++;
@@ -258,51 +403,51 @@ async function main() {
258
403
  break;
259
404
 
260
405
  case 'slow_down':
261
- // GitHub is asking us to slow down
262
- await log(`[RATE_LIMIT] GitHub requested slower polling - increasing interval to ${pollInterval * 1.5}s`);
263
- await sleep(pollInterval * 1500);
406
+ // GitHub asks clients to add 5s to the polling interval, then wait
407
+ // the updated interval before the next request.
408
+ currentPollIntervalMs += 5000;
409
+ await log(`[RATE_LIMIT] GitHub requested slower polling - increasing interval to ${currentPollIntervalMs / 1000}s`);
410
+ await sleep(currentPollIntervalMs);
264
411
  continue;
265
412
 
266
413
  case 'expired_token':
267
414
  await log('OAUTH_HELPER_264: Device code expired - authentication window closed');
268
415
  console.error('OAUTH_EXPIRED: Device code expired at line 264 - authentication window closed');
269
- clearInterval(heartbeatInterval);
270
- await cleanupPidFile();
271
- process.exit(1);
416
+ return finish('expired', 'expired_token', 1);
272
417
 
273
418
  case 'access_denied':
274
419
  await log('OAUTH_HELPER_270: User denied authorization request');
275
420
  console.error('OAUTH_ACCESS_DENIED: User denied authorization at line 270');
276
- clearInterval(heartbeatInterval);
277
- await cleanupPidFile();
278
- process.exit(1);
421
+ return finish('denied', 'access_denied', 1);
279
422
 
280
423
  default:
281
424
  await log('OAUTH_HELPER_276: Unknown error from GitHub during device flow polling');
282
425
  await log('[ERROR] GitHub returned an unrecognized OAuth polling response');
283
426
  console.error('OAUTH_UNKNOWN_RESPONSE: Unknown GitHub OAuth response at line 276');
427
+ return finish('failed', 'unknown_response', 1);
284
428
  }
285
429
  } else if (response.access_token) {
286
430
  // Success! We got the token
287
431
  await log('[SUCCESS] ✅ Token received from GitHub!');
288
432
  consecutiveErrors = 0; // Reset error counter
289
433
 
290
- // Store the token
291
- const stored = await storeToken(response.access_token);
434
+ let stored = false;
435
+ try {
436
+ stored = await storeToken(response.access_token);
437
+ } catch {
438
+ console.error('OAUTH_TOKEN_STORAGE_FAILED: Failed to store authentication token securely');
439
+ return finish('failed', 'token_storage_failed', 1);
440
+ }
292
441
 
293
442
  if (stored) {
294
443
  await log('[SUCCESS] ✅ OAuth authentication completed successfully');
295
444
  await log(`[STATS] Total attempts: ${attempts}, Time elapsed: ${Math.round((Date.now() - startTime) / 1000)}s`);
296
445
  console.log('✅ GitHub authentication successful! Token has been stored.');
297
- clearInterval(heartbeatInterval);
298
- await cleanupPidFile();
299
- process.exit(0);
446
+ return finish('success', 'success', 0);
300
447
  } else {
301
448
  await log('[ERROR] ❌ Failed to store token');
302
449
  console.error('❌ Failed to store authentication token');
303
- clearInterval(heartbeatInterval);
304
- await cleanupPidFile();
305
- process.exit(1);
450
+ return finish('failed', 'token_storage_failed', 1);
306
451
  }
307
452
  } else {
308
453
  // Reset error counter on successful communication
@@ -327,37 +472,33 @@ async function main() {
327
472
  if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
328
473
  await log('OAUTH_HELPER_323: Too many consecutive network errors, exiting');
329
474
  console.error(`OAUTH_NETWORK_FAILURE: Too many network errors (${MAX_CONSECUTIVE_ERRORS}) at line 323 - check internet connection`);
330
- clearInterval(heartbeatInterval);
331
- await cleanupPidFile();
332
- process.exit(1);
475
+ return finish('failed', 'network_failure', 1);
333
476
  }
334
477
  } else {
335
478
  // Non-network error, likely fatal
336
- await log('OAUTH_HELPER_330: Non-recoverable error');
479
+ await log(`OAUTH_HELPER_330: Non-recoverable error: ${sanitizeDiagnostic(error instanceof Error ? error.message : 'Unknown error')}`);
337
480
  console.error('OAUTH_FATAL_ERROR: Non-recoverable error at line 330');
338
- clearInterval(heartbeatInterval);
339
- await cleanupPidFile();
340
- process.exit(1);
481
+ return finish('failed', 'fatal_error', 1);
341
482
  }
342
483
  }
343
484
 
344
485
  // Wait before next poll
345
- await sleep(pollInterval * 1000);
486
+ await sleep(currentPollIntervalMs);
346
487
  }
347
488
 
348
489
  // Timeout reached
349
490
  await log('OAUTH_HELPER_342: OAuth authorization timed out');
350
491
  await log(`[STATS] Total attempts: ${attempts}, Time elapsed: ${Math.round((Date.now() - startTime) / 1000)}s`);
351
492
  console.error(`OAUTH_TIMEOUT: Authorization timed out at line 342 after ${Math.round((Date.now() - startTime) / 1000)}s - user did not authorize in time`);
352
- clearInterval(heartbeatInterval);
353
- await cleanupPidFile();
354
- process.exit(1);
493
+ return finish('timeout', 'timeout', 1);
355
494
  }
356
495
 
357
496
  // Run the main function
358
- main().catch(async () => {
359
- await log('Fatal error');
497
+ main().catch(async (error) => {
498
+ await log(`Fatal error: ${sanitizeDiagnostic(error instanceof Error ? error.message : 'Unknown error')}`);
360
499
  console.error('Fatal error in OAuth helper');
500
+ await writeTerminalResult('failed', 0, 'fatal_error');
501
+ await cleanupStateFile();
361
502
  await cleanupPidFile();
362
503
  process.exit(1);
363
504
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dollhousemcp/mcp-server",
3
- "version": "2.0.35",
3
+ "version": "2.0.36",
4
4
  "description": "DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.DollhouseMCP/mcp-server",
4
4
  "title": "DollhouseMCP",
5
5
  "description": "OSS to create Personas, Skills, Templates, Agents, and Memories to customize your AI experience.",
6
- "version": "2.0.35",
6
+ "version": "2.0.36",
7
7
  "homepage": "https://dollhousemcp.com",
8
8
  "repository": {
9
9
  "type": "git",
@@ -29,7 +29,7 @@
29
29
  {
30
30
  "registryType": "npm",
31
31
  "identifier": "@dollhousemcp/mcp-server",
32
- "version": "2.0.35",
32
+ "version": "2.0.36",
33
33
  "transport": {
34
34
  "type": "stdio"
35
35
  }