aios-core 4.2.13 → 4.2.14

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 (97) hide show
  1. package/.aios-core/core/code-intel/helpers/dev-helper.js +206 -0
  2. package/.aios-core/core/registry/registry-schema.json +166 -166
  3. package/.aios-core/core/synapse/diagnostics/collectors/hook-collector.js +3 -3
  4. package/.aios-core/data/entity-registry.yaml +27 -0
  5. package/.aios-core/development/scripts/approval-workflow.js +642 -642
  6. package/.aios-core/development/scripts/backup-manager.js +606 -606
  7. package/.aios-core/development/scripts/branch-manager.js +389 -389
  8. package/.aios-core/development/scripts/code-quality-improver.js +1311 -1311
  9. package/.aios-core/development/scripts/commit-message-generator.js +849 -849
  10. package/.aios-core/development/scripts/conflict-resolver.js +674 -674
  11. package/.aios-core/development/scripts/dependency-analyzer.js +637 -637
  12. package/.aios-core/development/scripts/diff-generator.js +351 -351
  13. package/.aios-core/development/scripts/elicitation-engine.js +384 -384
  14. package/.aios-core/development/scripts/elicitation-session-manager.js +299 -299
  15. package/.aios-core/development/scripts/git-wrapper.js +461 -461
  16. package/.aios-core/development/scripts/manifest-preview.js +244 -244
  17. package/.aios-core/development/scripts/metrics-tracker.js +775 -775
  18. package/.aios-core/development/scripts/modification-validator.js +554 -554
  19. package/.aios-core/development/scripts/pattern-learner.js +1224 -1224
  20. package/.aios-core/development/scripts/performance-analyzer.js +757 -757
  21. package/.aios-core/development/scripts/refactoring-suggester.js +1138 -1138
  22. package/.aios-core/development/scripts/rollback-handler.js +530 -530
  23. package/.aios-core/development/scripts/security-checker.js +358 -358
  24. package/.aios-core/development/scripts/template-engine.js +239 -239
  25. package/.aios-core/development/scripts/template-validator.js +278 -278
  26. package/.aios-core/development/scripts/test-generator.js +843 -843
  27. package/.aios-core/development/scripts/transaction-manager.js +589 -589
  28. package/.aios-core/development/scripts/usage-tracker.js +673 -673
  29. package/.aios-core/development/scripts/validate-filenames.js +226 -226
  30. package/.aios-core/development/scripts/version-tracker.js +526 -526
  31. package/.aios-core/development/scripts/yaml-validator.js +396 -396
  32. package/.aios-core/development/tasks/build-autonomous.md +10 -4
  33. package/.aios-core/development/tasks/create-service.md +23 -0
  34. package/.aios-core/development/tasks/dev-develop-story.md +12 -6
  35. package/.aios-core/development/tasks/dev-suggest-refactoring.md +7 -1
  36. package/.aios-core/development/tasks/publish-npm.md +3 -3
  37. package/.aios-core/hooks/unified/README.md +1 -1
  38. package/.aios-core/install-manifest.yaml +65 -61
  39. package/.aios-core/manifests/schema/manifest-schema.json +190 -190
  40. package/.aios-core/product/templates/component-react-tmpl.tsx +98 -98
  41. package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -102
  42. package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -205
  43. package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -175
  44. package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -175
  45. package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -300
  46. package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -152
  47. package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -222
  48. package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -154
  49. package/.aios-core/product/templates/eslintrc-security.json +32 -32
  50. package/.aios-core/product/templates/github-actions-cd.yml +212 -212
  51. package/.aios-core/product/templates/github-actions-ci.yml +172 -172
  52. package/.aios-core/product/templates/shock-report-tmpl.html +502 -502
  53. package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -240
  54. package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -233
  55. package/.aios-core/scripts/migrate-framework-docs.sh +300 -300
  56. package/README.en.md +747 -0
  57. package/README.md +4 -2
  58. package/bin/aios.js +7 -4
  59. package/package.json +1 -1
  60. package/packages/aios-pro-cli/src/recover.js +1 -1
  61. package/packages/installer/src/wizard/ide-config-generator.js +6 -6
  62. package/packages/installer/src/wizard/pro-setup.js +3 -3
  63. package/scripts/package-synapse.js +5 -5
  64. package/scripts/validate-package-completeness.js +3 -3
  65. package/.aios-core/.session/current-session.json +0 -14
  66. package/.aios-core/data/registry-update-log.jsonl +0 -191
  67. package/.aios-core/docs/SHARD-TRANSLATION-GUIDE.md +0 -335
  68. package/.aios-core/docs/component-creation-guide.md +0 -458
  69. package/.aios-core/docs/session-update-pattern.md +0 -307
  70. package/.aios-core/docs/standards/AIOS-FRAMEWORK-MASTER.md +0 -1963
  71. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-SUMMARY.md +0 -1190
  72. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1.md +0 -439
  73. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO.md +0 -5398
  74. package/.aios-core/docs/standards/V3-ARCHITECTURAL-DECISIONS.md +0 -523
  75. package/.aios-core/docs/template-syntax.md +0 -267
  76. package/.aios-core/docs/troubleshooting-guide.md +0 -625
  77. package/.aios-core/infrastructure/tests/utilities-audit-results.json +0 -501
  78. package/.aios-core/manifests/agents.csv +0 -29
  79. package/.aios-core/manifests/tasks.csv +0 -198
  80. package/.aios-core/manifests/workers.csv +0 -204
  81. package/.claude/rules/agent-authority.md +0 -105
  82. package/.claude/rules/coderabbit-integration.md +0 -93
  83. package/.claude/rules/ids-principles.md +0 -112
  84. package/.claude/rules/story-lifecycle.md +0 -139
  85. package/.claude/rules/workflow-execution.md +0 -150
  86. package/pro/README.md +0 -66
  87. package/pro/license/degradation.js +0 -220
  88. package/pro/license/errors.js +0 -450
  89. package/pro/license/feature-gate.js +0 -354
  90. package/pro/license/index.js +0 -181
  91. package/pro/license/license-api.js +0 -651
  92. package/pro/license/license-cache.js +0 -523
  93. package/pro/license/license-crypto.js +0 -303
  94. package/scripts/glue/README.md +0 -355
  95. package/scripts/glue/compose-agent-prompt.cjs +0 -362
  96. /package/.claude/hooks/{precompact-session-digest.js → precompact-session-digest.cjs} +0 -0
  97. /package/.claude/hooks/{synapse-engine.js → synapse-engine.cjs} +0 -0
@@ -1,523 +0,0 @@
1
- /**
2
- * License Cache Module
3
- *
4
- * Manages encrypted license cache file operations:
5
- * - Write encrypted cache with HMAC integrity
6
- * - Read and verify cache with tamper detection
7
- * - Expiry and grace period calculations
8
- * - Atomic file operations for data safety
9
- * - Pending deactivation tracking for offline scenarios
10
- *
11
- * Cache file: .aios/license.cache (encrypted, gitignored)
12
- *
13
- * @module pro/license/license-cache
14
- * @see ADR-PRO-003 - Feature Gating & Licensing
15
- * @see Story PRO-6 - License Key & Feature Gating System
16
- */
17
-
18
- 'use strict';
19
-
20
- const fs = require('fs');
21
- const path = require('path');
22
- const {
23
- generateMachineId,
24
- generateSalt,
25
- deriveCacheKey,
26
- encrypt,
27
- decrypt,
28
- computeHMAC,
29
- verifyHMAC,
30
- } = require('./license-crypto');
31
-
32
- /**
33
- * Configuration constants for cache operations.
34
- */
35
- const CONFIG = {
36
- // Default expiry settings (per ADR-PRO-003)
37
- DEFAULT_CACHE_VALID_DAYS: 30,
38
- DEFAULT_GRACE_PERIOD_DAYS: 7,
39
-
40
- // File paths
41
- AIOS_DIR: '.aios',
42
- CACHE_FILENAME: 'license.cache',
43
- PENDING_DEACTIVATION_FILENAME: 'pending-deactivation.json',
44
-
45
- // Cache version for migration support
46
- CACHE_VERSION: 1,
47
- };
48
-
49
- /**
50
- * Get the directory path for AIOS cache files.
51
- *
52
- * Uses project root (cwd) by default, falls back to home directory.
53
- *
54
- * @param {string} [baseDir] - Optional base directory override
55
- * @returns {string} Full path to .aios directory
56
- */
57
- function getAiosDir(baseDir = process.cwd()) {
58
- return path.join(baseDir, CONFIG.AIOS_DIR);
59
- }
60
-
61
- /**
62
- * Get the full path to the license cache file.
63
- *
64
- * @param {string} [baseDir] - Optional base directory override
65
- * @returns {string} Full path to license.cache
66
- */
67
- function getCachePath(baseDir) {
68
- return path.join(getAiosDir(baseDir), CONFIG.CACHE_FILENAME);
69
- }
70
-
71
- /**
72
- * Get the full path to the pending deactivation file.
73
- *
74
- * @param {string} [baseDir] - Optional base directory override
75
- * @returns {string} Full path to pending-deactivation.json
76
- */
77
- function getPendingDeactivationPath(baseDir) {
78
- return path.join(getAiosDir(baseDir), CONFIG.PENDING_DEACTIVATION_FILENAME);
79
- }
80
-
81
- /**
82
- * Ensure the .aios directory exists.
83
- *
84
- * @param {string} [baseDir] - Optional base directory override
85
- */
86
- function ensureAiosDir(baseDir) {
87
- const aiosDir = getAiosDir(baseDir);
88
- if (!fs.existsSync(aiosDir)) {
89
- fs.mkdirSync(aiosDir, { recursive: true });
90
- }
91
- }
92
-
93
- /**
94
- * Write license cache to disk with encryption and integrity protection.
95
- *
96
- * Uses atomic write (temp file → rename) for crash safety.
97
- *
98
- * Cache format on disk:
99
- * {
100
- * "encrypted": "<AES-256-GCM ciphertext>",
101
- * "iv": "<initialization vector>",
102
- * "tag": "<auth tag>",
103
- * "hmac": "<HMAC-SHA256 of encrypted content>",
104
- * "salt": "<PBKDF2 salt>",
105
- * "version": 1
106
- * }
107
- *
108
- * @param {object} data - License data to cache
109
- * @param {string} data.key - License key (PRO-XXXX-XXXX-XXXX-XXXX)
110
- * @param {string} data.activatedAt - ISO timestamp of activation
111
- * @param {string} data.expiresAt - ISO timestamp of expiry
112
- * @param {string[]} data.features - Array of enabled feature IDs
113
- * @param {object} data.seats - Seat usage info { used, max }
114
- * @param {number} [data.cacheValidDays=30] - Days until cache expires
115
- * @param {number} [data.gracePeriodDays=7] - Grace period after expiry
116
- * @param {string} [baseDir] - Optional base directory override
117
- * @returns {{ success: boolean, error?: string }} Write result
118
- */
119
- function writeLicenseCache(data, baseDir) {
120
- try {
121
- ensureAiosDir(baseDir);
122
-
123
- // Generate machine-specific encryption key
124
- const machineId = generateMachineId();
125
- const salt = generateSalt();
126
- const key = deriveCacheKey(machineId, salt);
127
-
128
- // Add metadata to cache data
129
- const cacheData = {
130
- ...data,
131
- machineId, // Store for verification (hashed, not sensitive)
132
- cacheValidDays: data.cacheValidDays || CONFIG.DEFAULT_CACHE_VALID_DAYS,
133
- gracePeriodDays: data.gracePeriodDays || CONFIG.DEFAULT_GRACE_PERIOD_DAYS,
134
- version: CONFIG.CACHE_VERSION,
135
- };
136
-
137
- // Encrypt the data
138
- const encrypted = encrypt(cacheData, key);
139
-
140
- // Compute HMAC over encrypted content for integrity
141
- const hmacData = JSON.stringify({
142
- ciphertext: encrypted.ciphertext,
143
- iv: encrypted.iv,
144
- tag: encrypted.tag,
145
- });
146
- const hmac = computeHMAC(hmacData, key);
147
-
148
- // Build cache file structure
149
- const cacheFile = {
150
- encrypted: encrypted.ciphertext,
151
- iv: encrypted.iv,
152
- tag: encrypted.tag,
153
- hmac,
154
- salt: salt.toString('hex'),
155
- version: CONFIG.CACHE_VERSION,
156
- };
157
-
158
- // Atomic write: temp file → rename
159
- const cachePath = getCachePath(baseDir);
160
- const tempPath = `${cachePath}.tmp.${process.pid}`;
161
-
162
- fs.writeFileSync(tempPath, JSON.stringify(cacheFile, null, 2), 'utf8');
163
- fs.renameSync(tempPath, cachePath);
164
-
165
- return { success: true };
166
- } catch (error) {
167
- return { success: false, error: error.message };
168
- }
169
- }
170
-
171
- /**
172
- * Read and verify license cache from disk.
173
- *
174
- * Performs:
175
- * 1. File existence check
176
- * 2. JSON parsing
177
- * 3. HMAC integrity verification
178
- * 4. AES-256-GCM decryption with auth tag verification
179
- * 5. Machine ID verification (cache non-portable)
180
- *
181
- * @param {string} [baseDir] - Optional base directory override
182
- * @returns {object|null} Decrypted cache data or null if invalid/missing
183
- */
184
- function readLicenseCache(baseDir) {
185
- try {
186
- const cachePath = getCachePath(baseDir);
187
-
188
- // Check file exists
189
- if (!fs.existsSync(cachePath)) {
190
- return null;
191
- }
192
-
193
- // Read and parse
194
- const fileContent = fs.readFileSync(cachePath, 'utf8');
195
- const cacheFile = JSON.parse(fileContent);
196
-
197
- // Validate structure
198
- if (!cacheFile.encrypted || !cacheFile.iv || !cacheFile.tag || !cacheFile.hmac || !cacheFile.salt) {
199
- return null;
200
- }
201
-
202
- // Derive key from current machine
203
- const machineId = generateMachineId();
204
- const salt = Buffer.from(cacheFile.salt, 'hex');
205
- const key = deriveCacheKey(machineId, salt);
206
-
207
- // Verify HMAC integrity
208
- const hmacData = JSON.stringify({
209
- ciphertext: cacheFile.encrypted,
210
- iv: cacheFile.iv,
211
- tag: cacheFile.tag,
212
- });
213
-
214
- if (!verifyHMAC(hmacData, key, cacheFile.hmac)) {
215
- // HMAC mismatch: cache is tampered or from different machine
216
- return null;
217
- }
218
-
219
- // Decrypt
220
- const encryptedData = {
221
- ciphertext: cacheFile.encrypted,
222
- iv: cacheFile.iv,
223
- tag: cacheFile.tag,
224
- };
225
-
226
- const decrypted = decrypt(encryptedData, key);
227
-
228
- // Verify machine ID matches (defense in depth)
229
- if (decrypted.machineId !== machineId) {
230
- return null;
231
- }
232
-
233
- return decrypted;
234
- } catch {
235
- // Any error (parse, decrypt, etc.) means cache is invalid
236
- return null;
237
- }
238
- }
239
-
240
- /**
241
- * Delete the license cache file.
242
- *
243
- * @param {string} [baseDir] - Optional base directory override
244
- * @returns {{ success: boolean, error?: string }} Delete result
245
- */
246
- function deleteLicenseCache(baseDir) {
247
- try {
248
- const cachePath = getCachePath(baseDir);
249
-
250
- if (fs.existsSync(cachePath)) {
251
- fs.unlinkSync(cachePath);
252
- }
253
-
254
- return { success: true };
255
- } catch (error) {
256
- return { success: false, error: error.message };
257
- }
258
- }
259
-
260
- /**
261
- * Check if the license cache is expired.
262
- *
263
- * Expired means: current date > activatedAt + cacheValidDays
264
- *
265
- * @param {object} cache - Decrypted cache data
266
- * @returns {boolean} true if cache is expired
267
- */
268
- function isExpired(cache) {
269
- if (!cache || !cache.activatedAt) {
270
- return true;
271
- }
272
-
273
- const activatedAt = new Date(cache.activatedAt);
274
- const cacheValidDays = cache.cacheValidDays || CONFIG.DEFAULT_CACHE_VALID_DAYS;
275
-
276
- const expiryDate = new Date(activatedAt);
277
- expiryDate.setDate(expiryDate.getDate() + cacheValidDays);
278
-
279
- return new Date() > expiryDate;
280
- }
281
-
282
- /**
283
- * Check if the license is in grace period.
284
- *
285
- * Grace period: cache is expired but within gracePeriodDays after expiry.
286
- *
287
- * @param {object} cache - Decrypted cache data
288
- * @returns {boolean} true if in grace period
289
- */
290
- function isInGracePeriod(cache) {
291
- if (!cache || !cache.activatedAt) {
292
- return false;
293
- }
294
-
295
- // Must be expired first
296
- if (!isExpired(cache)) {
297
- return false;
298
- }
299
-
300
- const activatedAt = new Date(cache.activatedAt);
301
- const cacheValidDays = cache.cacheValidDays || CONFIG.DEFAULT_CACHE_VALID_DAYS;
302
- const gracePeriodDays = cache.gracePeriodDays || CONFIG.DEFAULT_GRACE_PERIOD_DAYS;
303
-
304
- // Calculate grace period end
305
- const expiryDate = new Date(activatedAt);
306
- expiryDate.setDate(expiryDate.getDate() + cacheValidDays);
307
-
308
- const graceEndDate = new Date(expiryDate);
309
- graceEndDate.setDate(graceEndDate.getDate() + gracePeriodDays);
310
-
311
- return new Date() <= graceEndDate;
312
- }
313
-
314
- /**
315
- * Get the number of days remaining until cache expires.
316
- *
317
- * @param {object} cache - Decrypted cache data
318
- * @returns {number} Days remaining (negative if expired)
319
- */
320
- function getDaysRemaining(cache) {
321
- if (!cache || !cache.activatedAt) {
322
- return -1;
323
- }
324
-
325
- const activatedAt = new Date(cache.activatedAt);
326
- const cacheValidDays = cache.cacheValidDays || CONFIG.DEFAULT_CACHE_VALID_DAYS;
327
-
328
- const expiryDate = new Date(activatedAt);
329
- expiryDate.setDate(expiryDate.getDate() + cacheValidDays);
330
-
331
- const now = new Date();
332
- const diffMs = expiryDate - now;
333
- const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
334
-
335
- return diffDays;
336
- }
337
-
338
- /**
339
- * Get the expiry date of the cache.
340
- *
341
- * @param {object} cache - Decrypted cache data
342
- * @returns {Date|null} Expiry date or null
343
- */
344
- function getExpiryDate(cache) {
345
- if (!cache || !cache.activatedAt) {
346
- return null;
347
- }
348
-
349
- const activatedAt = new Date(cache.activatedAt);
350
- const cacheValidDays = cache.cacheValidDays || CONFIG.DEFAULT_CACHE_VALID_DAYS;
351
-
352
- const expiryDate = new Date(activatedAt);
353
- expiryDate.setDate(expiryDate.getDate() + cacheValidDays);
354
-
355
- return expiryDate;
356
- }
357
-
358
- /**
359
- * Get the license state based on cache.
360
- *
361
- * @param {object|null} cache - Decrypted cache data
362
- * @returns {'Active'|'Expired'|'Grace'|'Not Activated'} License state
363
- */
364
- function getLicenseState(cache) {
365
- if (!cache) {
366
- return 'Not Activated';
367
- }
368
-
369
- if (!isExpired(cache)) {
370
- return 'Active';
371
- }
372
-
373
- if (isInGracePeriod(cache)) {
374
- return 'Grace';
375
- }
376
-
377
- return 'Expired';
378
- }
379
-
380
- /**
381
- * Store a pending deactivation flag.
382
- *
383
- * Used when user deactivates offline - the deactivation will
384
- * be synced to the server on next online connection.
385
- *
386
- * @param {string} licenseKey - The license key being deactivated
387
- * @param {string} [baseDir] - Optional base directory override
388
- * @returns {{ success: boolean, error?: string }} Result
389
- */
390
- function setPendingDeactivation(licenseKey, baseDir) {
391
- try {
392
- ensureAiosDir(baseDir);
393
-
394
- const pendingPath = getPendingDeactivationPath(baseDir);
395
- const machineId = generateMachineId();
396
-
397
- const pendingData = {
398
- licenseKey,
399
- machineId,
400
- deactivatedAt: new Date().toISOString(),
401
- synced: false,
402
- };
403
-
404
- fs.writeFileSync(pendingPath, JSON.stringify(pendingData, null, 2), 'utf8');
405
-
406
- return { success: true };
407
- } catch (error) {
408
- return { success: false, error: error.message };
409
- }
410
- }
411
-
412
- /**
413
- * Check if there's a pending deactivation to sync.
414
- *
415
- * @param {string} [baseDir] - Optional base directory override
416
- * @returns {{ pending: boolean, data?: object }} Pending status and data
417
- */
418
- function hasPendingDeactivation(baseDir) {
419
- try {
420
- const pendingPath = getPendingDeactivationPath(baseDir);
421
-
422
- if (!fs.existsSync(pendingPath)) {
423
- return { pending: false };
424
- }
425
-
426
- const content = fs.readFileSync(pendingPath, 'utf8');
427
- const data = JSON.parse(content);
428
-
429
- if (data.synced) {
430
- return { pending: false };
431
- }
432
-
433
- return { pending: true, data };
434
- } catch {
435
- return { pending: false };
436
- }
437
- }
438
-
439
- /**
440
- * Mark pending deactivation as synced.
441
- *
442
- * @param {string} [baseDir] - Optional base directory override
443
- * @returns {{ success: boolean, error?: string }} Result
444
- */
445
- function markPendingDeactivationSynced(baseDir) {
446
- try {
447
- const pendingPath = getPendingDeactivationPath(baseDir);
448
-
449
- if (!fs.existsSync(pendingPath)) {
450
- return { success: true };
451
- }
452
-
453
- const content = fs.readFileSync(pendingPath, 'utf8');
454
- const data = JSON.parse(content);
455
-
456
- data.synced = true;
457
- data.syncedAt = new Date().toISOString();
458
-
459
- fs.writeFileSync(pendingPath, JSON.stringify(data, null, 2), 'utf8');
460
-
461
- return { success: true };
462
- } catch (error) {
463
- return { success: false, error: error.message };
464
- }
465
- }
466
-
467
- /**
468
- * Clear the pending deactivation file.
469
- *
470
- * @param {string} [baseDir] - Optional base directory override
471
- * @returns {{ success: boolean, error?: string }} Result
472
- */
473
- function clearPendingDeactivation(baseDir) {
474
- try {
475
- const pendingPath = getPendingDeactivationPath(baseDir);
476
-
477
- if (fs.existsSync(pendingPath)) {
478
- fs.unlinkSync(pendingPath);
479
- }
480
-
481
- return { success: true };
482
- } catch (error) {
483
- return { success: false, error: error.message };
484
- }
485
- }
486
-
487
- /**
488
- * Check if the cache file exists.
489
- *
490
- * @param {string} [baseDir] - Optional base directory override
491
- * @returns {boolean} true if cache file exists
492
- */
493
- function cacheExists(baseDir) {
494
- return fs.existsSync(getCachePath(baseDir));
495
- }
496
-
497
- module.exports = {
498
- // Core cache operations
499
- writeLicenseCache,
500
- readLicenseCache,
501
- deleteLicenseCache,
502
-
503
- // Expiry checks
504
- isExpired,
505
- isInGracePeriod,
506
- getDaysRemaining,
507
- getExpiryDate,
508
- getLicenseState,
509
-
510
- // Pending deactivation (offline scenario)
511
- setPendingDeactivation,
512
- hasPendingDeactivation,
513
- markPendingDeactivationSynced,
514
- clearPendingDeactivation,
515
-
516
- // Utilities
517
- cacheExists,
518
- getCachePath,
519
- getAiosDir,
520
-
521
- // Exported for testing
522
- _CONFIG: CONFIG,
523
- };