kanban-ai 0.22.0 → 0.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.js +8 -1
- package/dist/constants.test.js +4 -0
- package/dist/env.js +6 -1
- package/dist/env.test.js +24 -2
- package/dist/index.js +1 -1
- package/dist/index.test.js +1 -0
- package/dist/migration.js +180 -0
- package/dist/migration.test.js +107 -0
- package/dist/paths.js +119 -0
- package/dist/paths.test.js +154 -0
- package/dist/updates.test.js +1 -0
- package/package.json +1 -1
package/dist/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CACHE_SUBDIR_BINARY = exports.CACHE_DIR_NAME = exports.KANBANAI_ASSUME_NO_ENV = exports.KANBANAI_ASSUME_YES_ENV = exports.KANBANAI_NO_UPDATE_CHECK_ENV = exports.KANBANAI_GITHUB_REPO_ENV = exports.KANBANAI_BINARY_VERSION_ENV = exports.KANBANAI_HOME_ENV = exports.DEFAULT_GITHUB_REPO = void 0;
|
|
3
|
+
exports.CACHE_SUBDIR = exports.CONFIG_SUBDIR = exports.CACHE_SUBDIR_BINARY = exports.CACHE_DIR_NAME = exports.XDG_CACHE_HOME_ENV = exports.XDG_CONFIG_HOME_ENV = exports.KANBANAI_ASSUME_NO_ENV = exports.KANBANAI_ASSUME_YES_ENV = exports.KANBANAI_NO_UPDATE_CHECK_ENV = exports.KANBANAI_GITHUB_REPO_ENV = exports.KANBANAI_BINARY_VERSION_ENV = exports.KANBANAI_HOME_ENV = exports.DEFAULT_GITHUB_REPO = void 0;
|
|
4
4
|
exports.DEFAULT_GITHUB_REPO = 'activadee/kanban-ai';
|
|
5
5
|
exports.KANBANAI_HOME_ENV = 'KANBANAI_HOME';
|
|
6
6
|
exports.KANBANAI_BINARY_VERSION_ENV = 'KANBANAI_BINARY_VERSION';
|
|
@@ -8,5 +8,12 @@ exports.KANBANAI_GITHUB_REPO_ENV = 'KANBANAI_GITHUB_REPO';
|
|
|
8
8
|
exports.KANBANAI_NO_UPDATE_CHECK_ENV = 'KANBANAI_NO_UPDATE_CHECK';
|
|
9
9
|
exports.KANBANAI_ASSUME_YES_ENV = 'KANBANAI_ASSUME_YES';
|
|
10
10
|
exports.KANBANAI_ASSUME_NO_ENV = 'KANBANAI_ASSUME_NO';
|
|
11
|
+
// XDG Base Directory Specification environment variables
|
|
12
|
+
exports.XDG_CONFIG_HOME_ENV = 'XDG_CONFIG_HOME';
|
|
13
|
+
exports.XDG_CACHE_HOME_ENV = 'XDG_CACHE_HOME';
|
|
14
|
+
// Legacy directory name for backward compatibility
|
|
11
15
|
exports.CACHE_DIR_NAME = '.kanbanAI';
|
|
12
16
|
exports.CACHE_SUBDIR_BINARY = 'binary';
|
|
17
|
+
// New XDG-compliant subdirectory names
|
|
18
|
+
exports.CONFIG_SUBDIR = 'kanban-ai';
|
|
19
|
+
exports.CACHE_SUBDIR = 'kanban-ai';
|
package/dist/constants.test.js
CHANGED
|
@@ -13,5 +13,9 @@ const constants_1 = require("./constants");
|
|
|
13
13
|
(0, vitest_1.expect)(constants_1.KANBANAI_ASSUME_NO_ENV).toBe('KANBANAI_ASSUME_NO');
|
|
14
14
|
(0, vitest_1.expect)(constants_1.CACHE_DIR_NAME).toBe('.kanbanAI');
|
|
15
15
|
(0, vitest_1.expect)(constants_1.CACHE_SUBDIR_BINARY).toBe('binary');
|
|
16
|
+
(0, vitest_1.expect)(constants_1.XDG_CONFIG_HOME_ENV).toBe('XDG_CONFIG_HOME');
|
|
17
|
+
(0, vitest_1.expect)(constants_1.XDG_CACHE_HOME_ENV).toBe('XDG_CACHE_HOME');
|
|
18
|
+
(0, vitest_1.expect)(constants_1.CONFIG_SUBDIR).toBe('kanban-ai');
|
|
19
|
+
(0, vitest_1.expect)(constants_1.CACHE_SUBDIR).toBe('kanban-ai');
|
|
16
20
|
});
|
|
17
21
|
});
|
package/dist/env.js
CHANGED
|
@@ -7,10 +7,14 @@ exports.resolveEnvOptions = resolveEnvOptions;
|
|
|
7
7
|
const node_os_1 = __importDefault(require("node:os"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
9
|
const constants_1 = require("./constants");
|
|
10
|
+
const paths_1 = require("./paths");
|
|
10
11
|
function resolveEnvOptions() {
|
|
12
|
+
// Determine home directory - prefer KANBANAI_HOME for legacy compatibility
|
|
11
13
|
const homeEnv = process.env[constants_1.KANBANAI_HOME_ENV] || process.env.HOME || process.env.USERPROFILE;
|
|
12
14
|
const home = homeEnv || node_os_1.default.homedir();
|
|
13
|
-
|
|
15
|
+
// Resolve XDG-compliant paths
|
|
16
|
+
const configDir = (0, paths_1.getConfigDir)(home);
|
|
17
|
+
const baseCacheDir = node_path_1.default.join((0, paths_1.getCacheDir)(home), constants_1.CACHE_SUBDIR_BINARY);
|
|
14
18
|
const githubRepo = process.env[constants_1.KANBANAI_GITHUB_REPO_ENV] || constants_1.DEFAULT_GITHUB_REPO;
|
|
15
19
|
const binaryVersionOverride = process.env[constants_1.KANBANAI_BINARY_VERSION_ENV] || undefined;
|
|
16
20
|
const noUpdateCheck = toBoolEnv(process.env[constants_1.KANBANAI_NO_UPDATE_CHECK_ENV]);
|
|
@@ -19,6 +23,7 @@ function resolveEnvOptions() {
|
|
|
19
23
|
return {
|
|
20
24
|
githubRepo,
|
|
21
25
|
baseCacheDir,
|
|
26
|
+
configDir,
|
|
22
27
|
binaryVersionOverride,
|
|
23
28
|
noUpdateCheck,
|
|
24
29
|
assumeYes,
|
package/dist/env.test.js
CHANGED
|
@@ -20,9 +20,12 @@ const originalEnv = { ...process.env };
|
|
|
20
20
|
delete process.env.KANBANAI_NO_UPDATE_CHECK;
|
|
21
21
|
delete process.env.KANBANAI_ASSUME_YES;
|
|
22
22
|
delete process.env.KANBANAI_ASSUME_NO;
|
|
23
|
+
delete process.env.XDG_CONFIG_HOME;
|
|
24
|
+
delete process.env.XDG_CACHE_HOME;
|
|
23
25
|
const env = (0, env_1.resolveEnvOptions)();
|
|
24
26
|
(0, vitest_1.expect)(env.githubRepo).toBe('activadee/kanban-ai');
|
|
25
|
-
(0, vitest_1.expect)(env.baseCacheDir.endsWith(node_path_1.default.join('.
|
|
27
|
+
(0, vitest_1.expect)(env.baseCacheDir.endsWith(node_path_1.default.join('.cache', 'kanban-ai', 'binary'))).toBe(true);
|
|
28
|
+
(0, vitest_1.expect)(env.configDir.endsWith(node_path_1.default.join('.config', 'kanban-ai'))).toBe(true);
|
|
26
29
|
(0, vitest_1.expect)(env.binaryVersionOverride).toBeUndefined();
|
|
27
30
|
(0, vitest_1.expect)(env.noUpdateCheck).toBe(false);
|
|
28
31
|
(0, vitest_1.expect)(env.assumeYes).toBe(false);
|
|
@@ -35,12 +38,31 @@ const originalEnv = { ...process.env };
|
|
|
35
38
|
process.env.KANBANAI_NO_UPDATE_CHECK = 'true';
|
|
36
39
|
process.env.KANBANAI_ASSUME_YES = '1';
|
|
37
40
|
process.env.KANBANAI_ASSUME_NO = 'yes';
|
|
41
|
+
process.env.XDG_CONFIG_HOME = '/custom/config';
|
|
42
|
+
process.env.XDG_CACHE_HOME = '/custom/cache';
|
|
38
43
|
const env = (0, env_1.resolveEnvOptions)();
|
|
39
44
|
(0, vitest_1.expect)(env.githubRepo).toBe('someone/else');
|
|
40
|
-
(0, vitest_1.expect)(env.baseCacheDir).toBe(
|
|
45
|
+
(0, vitest_1.expect)(env.baseCacheDir).toBe('/custom/cache/kanban-ai/binary');
|
|
46
|
+
(0, vitest_1.expect)(env.configDir).toBe('/custom/config/kanban-ai');
|
|
41
47
|
(0, vitest_1.expect)(env.binaryVersionOverride).toBe('1.2.3');
|
|
42
48
|
(0, vitest_1.expect)(env.noUpdateCheck).toBe(true);
|
|
43
49
|
(0, vitest_1.expect)(env.assumeYes).toBe(true);
|
|
44
50
|
(0, vitest_1.expect)(env.assumeNo).toBe(true);
|
|
45
51
|
});
|
|
52
|
+
(0, vitest_1.it)('uses KANBANAI_HOME for home directory when set', () => {
|
|
53
|
+
process.env.KANBANAI_HOME = '/custom/home';
|
|
54
|
+
delete process.env.XDG_CONFIG_HOME;
|
|
55
|
+
delete process.env.XDG_CACHE_HOME;
|
|
56
|
+
const env = (0, env_1.resolveEnvOptions)();
|
|
57
|
+
(0, vitest_1.expect)(env.baseCacheDir).toBe('/custom/home/.cache/kanban-ai/binary');
|
|
58
|
+
(0, vitest_1.expect)(env.configDir).toBe('/custom/home/.config/kanban-ai');
|
|
59
|
+
});
|
|
60
|
+
(0, vitest_1.it)('respects XDG environment variables', () => {
|
|
61
|
+
delete process.env.KANBANAI_HOME;
|
|
62
|
+
process.env.XDG_CONFIG_HOME = '/xdg/config';
|
|
63
|
+
process.env.XDG_CACHE_HOME = '/xdg/cache';
|
|
64
|
+
const env = (0, env_1.resolveEnvOptions)();
|
|
65
|
+
(0, vitest_1.expect)(env.configDir).toBe('/xdg/config/kanban-ai');
|
|
66
|
+
(0, vitest_1.expect)(env.baseCacheDir).toBe('/xdg/cache/kanban-ai/binary');
|
|
67
|
+
});
|
|
46
68
|
});
|
package/dist/index.js
CHANGED
|
@@ -40,7 +40,7 @@ async function runCli() {
|
|
|
40
40
|
const platformArch = (0, platform_1.detectPlatformArch)();
|
|
41
41
|
const binaryInfo = (0, platform_1.resolveBinaryInfo)(platformArch.platform, platformArch.arch);
|
|
42
42
|
const githubApiCache = {
|
|
43
|
-
dir: node_path_1.default.join(
|
|
43
|
+
dir: node_path_1.default.join(effectiveEnv.configDir, "github-api"),
|
|
44
44
|
};
|
|
45
45
|
const explicitVersion = cliOptions.binaryVersion
|
|
46
46
|
? (0, version_1.cleanVersionTag)(cliOptions.binaryVersion)
|
package/dist/index.test.js
CHANGED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.migrationNeeded = migrationNeeded;
|
|
7
|
+
exports.getMigrationItems = getMigrationItems;
|
|
8
|
+
exports.migrateFromLegacy = migrateFromLegacy;
|
|
9
|
+
exports.getMigrationStatus = getMigrationStatus;
|
|
10
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const paths_1 = require("./paths");
|
|
13
|
+
/**
|
|
14
|
+
* Check if migration is needed (legacy directory exists)
|
|
15
|
+
* @returns true if legacy directory exists and new directories don't
|
|
16
|
+
*/
|
|
17
|
+
function migrationNeeded() {
|
|
18
|
+
const legacyExists = node_fs_1.default.existsSync((0, paths_1.getLegacyDir)());
|
|
19
|
+
// Migration is needed if legacy exists and config doesn't
|
|
20
|
+
const configExists = node_fs_1.default.existsSync((0, paths_1.getConfigDir)());
|
|
21
|
+
return legacyExists && !configExists;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get a list of files/directories that need to be migrated from legacy location
|
|
25
|
+
* @returns Object with configItems and cacheItems arrays
|
|
26
|
+
*/
|
|
27
|
+
function getMigrationItems() {
|
|
28
|
+
const legacyDir = (0, paths_1.getLegacyDir)();
|
|
29
|
+
const configItems = [];
|
|
30
|
+
const cacheItems = [];
|
|
31
|
+
try {
|
|
32
|
+
const entries = node_fs_1.default.readdirSync(legacyDir, { withFileTypes: true });
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
const fullPath = node_path_1.default.join(legacyDir, entry.name);
|
|
35
|
+
// GitHub API cache should go to config
|
|
36
|
+
if (entry.name === 'github-api' && entry.isDirectory()) {
|
|
37
|
+
configItems.push(entry.name);
|
|
38
|
+
}
|
|
39
|
+
// Everything else (binary, worktrees) goes to cache
|
|
40
|
+
else {
|
|
41
|
+
cacheItems.push(entry.name);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// Directory doesn't exist or can't be read
|
|
47
|
+
return { configItems: [], cacheItems: [] };
|
|
48
|
+
}
|
|
49
|
+
return { configItems, cacheItems };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Perform the migration from legacy .kanbanAI directory to XDG-compliant locations
|
|
53
|
+
* @param options Options for controlling migration behavior
|
|
54
|
+
* @returns MigrationResult with details about the migration
|
|
55
|
+
*/
|
|
56
|
+
async function migrateFromLegacy(options = {}) {
|
|
57
|
+
const { dryRun = false, force = false, onProgress } = options;
|
|
58
|
+
const result = {
|
|
59
|
+
success: false,
|
|
60
|
+
configMigrated: false,
|
|
61
|
+
cacheMigrated: false,
|
|
62
|
+
errors: [],
|
|
63
|
+
};
|
|
64
|
+
try {
|
|
65
|
+
const legacyDir = (0, paths_1.getLegacyDir)();
|
|
66
|
+
const configDir = (0, paths_1.getConfigDir)();
|
|
67
|
+
const cacheDir = (0, paths_1.getCacheDir)();
|
|
68
|
+
if (!node_fs_1.default.existsSync(legacyDir)) {
|
|
69
|
+
onProgress?.('No legacy directory found. Migration not needed.');
|
|
70
|
+
result.success = true;
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
if (node_fs_1.default.existsSync(configDir) && !force) {
|
|
74
|
+
onProgress?.('XDG-compliant directories already exist. Migration not needed.');
|
|
75
|
+
result.success = true;
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
onProgress?.(`Starting migration from ${legacyDir}`);
|
|
79
|
+
// Create directories if they don't exist
|
|
80
|
+
if (!dryRun) {
|
|
81
|
+
node_fs_1.default.mkdirSync(configDir, { recursive: true });
|
|
82
|
+
node_fs_1.default.mkdirSync(cacheDir, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
// Get items to migrate
|
|
85
|
+
const { configItems, cacheItems } = getMigrationItems();
|
|
86
|
+
if (configItems.length > 0) {
|
|
87
|
+
onProgress?.(`Migrating config items: ${configItems.join(', ')}`);
|
|
88
|
+
for (const item of configItems) {
|
|
89
|
+
const source = node_path_1.default.join(legacyDir, item);
|
|
90
|
+
const destination = node_path_1.default.join(configDir, item);
|
|
91
|
+
if (dryRun) {
|
|
92
|
+
onProgress?.(`[DRY RUN] Would copy ${source} to ${destination}`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
onProgress?.(`Copying ${source} to ${destination}`);
|
|
96
|
+
await copyRecursive(source, destination);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!dryRun) {
|
|
100
|
+
result.configMigrated = true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (cacheItems.length > 0) {
|
|
104
|
+
onProgress?.(`Migrating cache items: ${cacheItems.join(', ')}`);
|
|
105
|
+
for (const item of cacheItems) {
|
|
106
|
+
const source = node_path_1.default.join(legacyDir, item);
|
|
107
|
+
const destination = node_path_1.default.join(cacheDir, item);
|
|
108
|
+
if (dryRun) {
|
|
109
|
+
onProgress?.(`[DRY RUN] Would copy ${source} to ${destination}`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
onProgress?.(`Copying ${source} to ${destination}`);
|
|
113
|
+
await copyRecursive(source, destination);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!dryRun) {
|
|
117
|
+
result.cacheMigrated = true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
result.success = true;
|
|
121
|
+
onProgress?.('Migration completed successfully!');
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
125
|
+
result.errors.push(errorMessage);
|
|
126
|
+
onProgress?.(`Migration failed: ${errorMessage}`);
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Copy a directory recursively
|
|
132
|
+
*/
|
|
133
|
+
async function copyRecursive(source, destination) {
|
|
134
|
+
// Check if source is a directory
|
|
135
|
+
const stats = node_fs_1.default.statSync(source);
|
|
136
|
+
if (stats.isDirectory()) {
|
|
137
|
+
// Create destination directory
|
|
138
|
+
node_fs_1.default.mkdirSync(destination, { recursive: true });
|
|
139
|
+
// Copy all contents
|
|
140
|
+
const entries = node_fs_1.default.readdirSync(source, { withFileTypes: true });
|
|
141
|
+
for (const entry of entries) {
|
|
142
|
+
const sourcePath = node_path_1.default.join(source, entry.name);
|
|
143
|
+
const destPath = node_path_1.default.join(destination, entry.name);
|
|
144
|
+
if (entry.isDirectory()) {
|
|
145
|
+
await copyRecursive(sourcePath, destPath);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
node_fs_1.default.copyFileSync(sourcePath, destPath);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// It's a file, just copy it
|
|
154
|
+
node_fs_1.default.copyFileSync(source, destination);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get the status of migration without performing it
|
|
159
|
+
* @returns Object describing current migration status
|
|
160
|
+
*/
|
|
161
|
+
function getMigrationStatus() {
|
|
162
|
+
const legacyDir = (0, paths_1.getLegacyDir)();
|
|
163
|
+
const configDir = (0, paths_1.getConfigDir)();
|
|
164
|
+
const cacheDir = (0, paths_1.getCacheDir)();
|
|
165
|
+
const legacyExists = node_fs_1.default.existsSync(legacyDir);
|
|
166
|
+
const configExists = node_fs_1.default.existsSync(configDir);
|
|
167
|
+
const cacheExists = node_fs_1.default.existsSync(cacheDir);
|
|
168
|
+
const needsMigration = legacyExists && (!configExists || !cacheExists);
|
|
169
|
+
let pendingItems = { configItems: [], cacheItems: [] };
|
|
170
|
+
if (needsMigration) {
|
|
171
|
+
pendingItems = getMigrationItems();
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
legacyExists,
|
|
175
|
+
configExists,
|
|
176
|
+
cacheExists,
|
|
177
|
+
needsMigration,
|
|
178
|
+
pendingItems,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const migration_1 = require("./migration");
|
|
10
|
+
(0, vitest_1.describe)('Migration', () => {
|
|
11
|
+
const testHome = '/tmp/kanban-ai-test';
|
|
12
|
+
const legacyDir = node_path_1.default.join(testHome, '.kanbanAI');
|
|
13
|
+
const configDir = node_path_1.default.join(testHome, '.config', 'kanban-ai');
|
|
14
|
+
const cacheDir = node_path_1.default.join(testHome, '.cache', 'kanban-ai');
|
|
15
|
+
(0, vitest_1.beforeEach)(() => {
|
|
16
|
+
// Create test directory structure
|
|
17
|
+
node_fs_1.default.mkdirSync(legacyDir, { recursive: true });
|
|
18
|
+
node_fs_1.default.mkdirSync(node_path_1.default.join(legacyDir, 'binary'), { recursive: true });
|
|
19
|
+
node_fs_1.default.mkdirSync(node_path_1.default.join(legacyDir, 'github-api'), { recursive: true });
|
|
20
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(legacyDir, 'binary', 'test'), 'test binary');
|
|
21
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(legacyDir, 'github-api', 'test'), 'test cache');
|
|
22
|
+
});
|
|
23
|
+
(0, vitest_1.afterEach)(() => {
|
|
24
|
+
// Cleanup test directories
|
|
25
|
+
node_fs_1.default.rmSync(testHome, { recursive: true, force: true });
|
|
26
|
+
vitest_1.vi.unstubAllEnvs();
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.describe)('migrationNeeded', () => {
|
|
29
|
+
(0, vitest_1.test)('returns true when legacy exists but config does not', () => {
|
|
30
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
31
|
+
(0, vitest_1.expect)((0, migration_1.migrationNeeded)()).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
(0, vitest_1.test)('returns false when both legacy and config exist', () => {
|
|
34
|
+
node_fs_1.default.mkdirSync(configDir, { recursive: true });
|
|
35
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
36
|
+
(0, vitest_1.expect)((0, migration_1.migrationNeeded)()).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
(0, vitest_1.test)('returns false when legacy does not exist', () => {
|
|
39
|
+
node_fs_1.default.rmSync(legacyDir, { recursive: true, force: true });
|
|
40
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
41
|
+
(0, vitest_1.expect)((0, migration_1.migrationNeeded)()).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
(0, vitest_1.describe)('getMigrationItems', () => {
|
|
45
|
+
(0, vitest_1.test)('identifies github-api as config item', () => {
|
|
46
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
47
|
+
const { configItems } = (0, migration_1.getMigrationItems)();
|
|
48
|
+
(0, vitest_1.expect)(configItems).toContain('github-api');
|
|
49
|
+
});
|
|
50
|
+
(0, vitest_1.test)('identifies binary as cache item', () => {
|
|
51
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
52
|
+
const { cacheItems } = (0, migration_1.getMigrationItems)();
|
|
53
|
+
(0, vitest_1.expect)(cacheItems).toContain('binary');
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
(0, vitest_1.describe)('migrateFromLegacy', () => {
|
|
57
|
+
(0, vitest_1.test)('performs dry run without creating directories', async () => {
|
|
58
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
59
|
+
const progress = [];
|
|
60
|
+
const result = await (0, migration_1.migrateFromLegacy)({
|
|
61
|
+
dryRun: true,
|
|
62
|
+
onProgress: (msg) => progress.push(msg),
|
|
63
|
+
});
|
|
64
|
+
(0, vitest_1.expect)(result.success).toBe(true);
|
|
65
|
+
(0, vitest_1.expect)(result.configMigrated).toBe(false);
|
|
66
|
+
(0, vitest_1.expect)(result.cacheMigrated).toBe(false);
|
|
67
|
+
(0, vitest_1.expect)(progress.some(msg => msg.includes('[DRY RUN]'))).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
(0, vitest_1.test)('creates XDG directories when migrating', async () => {
|
|
70
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
71
|
+
const result = await (0, migration_1.migrateFromLegacy)({ force: true });
|
|
72
|
+
(0, vitest_1.expect)(result.success).toBe(true);
|
|
73
|
+
(0, vitest_1.expect)(node_fs_1.default.existsSync(configDir)).toBe(true);
|
|
74
|
+
(0, vitest_1.expect)(node_fs_1.default.existsSync(cacheDir)).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
(0, vitest_1.test)('copies github-api to config directory', async () => {
|
|
77
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
78
|
+
await (0, migration_1.migrateFromLegacy)({ force: true });
|
|
79
|
+
const githubApiPath = node_path_1.default.join(configDir, 'github-api', 'test');
|
|
80
|
+
(0, vitest_1.expect)(node_fs_1.default.existsSync(githubApiPath)).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
(0, vitest_1.test)('copies binary to cache directory', async () => {
|
|
83
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
84
|
+
await (0, migration_1.migrateFromLegacy)({ force: true });
|
|
85
|
+
const binaryPath = node_path_1.default.join(cacheDir, 'binary', 'test');
|
|
86
|
+
(0, vitest_1.expect)(node_fs_1.default.existsSync(binaryPath)).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
(0, vitest_1.describe)('getMigrationStatus', () => {
|
|
90
|
+
(0, vitest_1.test)('returns comprehensive status', () => {
|
|
91
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
92
|
+
const status = (0, migration_1.getMigrationStatus)();
|
|
93
|
+
(0, vitest_1.expect)(status).toHaveProperty('legacyExists');
|
|
94
|
+
(0, vitest_1.expect)(status).toHaveProperty('configExists');
|
|
95
|
+
(0, vitest_1.expect)(status).toHaveProperty('cacheExists');
|
|
96
|
+
(0, vitest_1.expect)(status).toHaveProperty('needsMigration');
|
|
97
|
+
(0, vitest_1.expect)(status).toHaveProperty('pendingItems');
|
|
98
|
+
});
|
|
99
|
+
(0, vitest_1.test)('indicates migration is needed', () => {
|
|
100
|
+
vitest_1.vi.stubEnv('HOME', testHome);
|
|
101
|
+
const status = (0, migration_1.getMigrationStatus)();
|
|
102
|
+
(0, vitest_1.expect)(status.legacyExists).toBe(true);
|
|
103
|
+
(0, vitest_1.expect)(status.configExists).toBe(false);
|
|
104
|
+
(0, vitest_1.expect)(status.needsMigration).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LEGACY_DIR_NAME = exports.CACHE_SUBDIR = exports.CONFIG_SUBDIR = exports.XDG_CACHE_HOME_ENV = exports.XDG_CONFIG_HOME_ENV = void 0;
|
|
7
|
+
exports.getConfigDir = getConfigDir;
|
|
8
|
+
exports.getCacheDir = getCacheDir;
|
|
9
|
+
exports.getLegacyDir = getLegacyDir;
|
|
10
|
+
exports.legacyDirExists = legacyDirExists;
|
|
11
|
+
exports.getConfigSubdirPath = getConfigSubdirPath;
|
|
12
|
+
exports.getCacheSubdirPath = getCacheSubdirPath;
|
|
13
|
+
exports.getPathInfo = getPathInfo;
|
|
14
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
15
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
16
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
17
|
+
// XDG Base Directory Specification constants
|
|
18
|
+
exports.XDG_CONFIG_HOME_ENV = 'XDG_CONFIG_HOME';
|
|
19
|
+
exports.XDG_CACHE_HOME_ENV = 'XDG_CACHE_HOME';
|
|
20
|
+
// Default subdirectory names
|
|
21
|
+
exports.CONFIG_SUBDIR = 'kanban-ai';
|
|
22
|
+
exports.CACHE_SUBDIR = 'kanban-ai';
|
|
23
|
+
// Legacy directory name for migration detection
|
|
24
|
+
exports.LEGACY_DIR_NAME = '.kanbanAI';
|
|
25
|
+
/**
|
|
26
|
+
* Check if running on Windows platform
|
|
27
|
+
*/
|
|
28
|
+
function isWindows() {
|
|
29
|
+
return process.platform === 'win32';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get the user's config directory following XDG Base Directory Specification
|
|
33
|
+
* On Windows, uses APPDATA if XDG_CONFIG_HOME is not set
|
|
34
|
+
* @param customHome Optional custom home directory (useful for testing)
|
|
35
|
+
* @returns The config directory path
|
|
36
|
+
*/
|
|
37
|
+
function getConfigDir(customHome) {
|
|
38
|
+
const home = customHome || node_os_1.default.homedir();
|
|
39
|
+
const xdgConfigHome = process.env[exports.XDG_CONFIG_HOME_ENV];
|
|
40
|
+
if (xdgConfigHome) {
|
|
41
|
+
return node_path_1.default.join(xdgConfigHome, exports.CONFIG_SUBDIR);
|
|
42
|
+
}
|
|
43
|
+
// On Windows, use APPDATA as the conventional location
|
|
44
|
+
if (isWindows()) {
|
|
45
|
+
const appData = process.env.APPDATA || node_path_1.default.join(home, 'AppData', 'Roaming');
|
|
46
|
+
return node_path_1.default.join(appData, exports.CONFIG_SUBDIR);
|
|
47
|
+
}
|
|
48
|
+
// On Unix/Linux, use XDG default
|
|
49
|
+
return node_path_1.default.join(home, '.config', exports.CONFIG_SUBDIR);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the user's cache directory following XDG Base Directory Specification
|
|
53
|
+
* On Windows, uses LOCALAPPDATA if XDG_CACHE_HOME is not set
|
|
54
|
+
* @param customHome Optional custom home directory (useful for testing)
|
|
55
|
+
* @returns The cache directory path
|
|
56
|
+
*/
|
|
57
|
+
function getCacheDir(customHome) {
|
|
58
|
+
const home = customHome || node_os_1.default.homedir();
|
|
59
|
+
const xdgCacheHome = process.env[exports.XDG_CACHE_HOME_ENV];
|
|
60
|
+
if (xdgCacheHome) {
|
|
61
|
+
return node_path_1.default.join(xdgCacheHome, exports.CACHE_SUBDIR);
|
|
62
|
+
}
|
|
63
|
+
// On Windows, use LOCALAPPDATA as the conventional location
|
|
64
|
+
if (isWindows()) {
|
|
65
|
+
const localAppData = process.env.LOCALAPPDATA || node_path_1.default.join(home, 'AppData', 'Local');
|
|
66
|
+
return node_path_1.default.join(localAppData, exports.CACHE_SUBDIR);
|
|
67
|
+
}
|
|
68
|
+
// On Unix/Linux, use XDG default
|
|
69
|
+
return node_path_1.default.join(home, '.cache', exports.CACHE_SUBDIR);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get the legacy .kanbanAI directory path for migration detection
|
|
73
|
+
* @param customHome Optional custom home directory (useful for testing)
|
|
74
|
+
* @returns The legacy directory path
|
|
75
|
+
*/
|
|
76
|
+
function getLegacyDir(customHome) {
|
|
77
|
+
const home = customHome || node_os_1.default.homedir();
|
|
78
|
+
return node_path_1.default.join(home, exports.LEGACY_DIR_NAME);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Check if the legacy .kanbanAI directory exists
|
|
82
|
+
* @param customHome Optional custom home directory (useful for testing)
|
|
83
|
+
* @returns true if legacy directory exists
|
|
84
|
+
*/
|
|
85
|
+
function legacyDirExists(customHome) {
|
|
86
|
+
const legacyPath = getLegacyDir(customHome);
|
|
87
|
+
return node_fs_1.default.existsSync(legacyPath);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get the path for a specific subdirectory within the config directory
|
|
91
|
+
* @param subdirName The subdirectory name
|
|
92
|
+
* @returns The full path to the subdirectory
|
|
93
|
+
*/
|
|
94
|
+
function getConfigSubdirPath(subdirName) {
|
|
95
|
+
return node_path_1.default.join(getConfigDir(), subdirName);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get the path for a specific subdirectory within the cache directory
|
|
99
|
+
* @param subdirName The subdirectory name
|
|
100
|
+
* @returns The full path to the subdirectory
|
|
101
|
+
*/
|
|
102
|
+
function getCacheSubdirPath(subdirName) {
|
|
103
|
+
return node_path_1.default.join(getCacheDir(), subdirName);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get comprehensive path information for debugging purposes
|
|
107
|
+
* @returns PathInfo object with all relevant paths
|
|
108
|
+
*/
|
|
109
|
+
function getPathInfo() {
|
|
110
|
+
return {
|
|
111
|
+
configDir: getConfigDir(),
|
|
112
|
+
cacheDir: getCacheDir(),
|
|
113
|
+
legacyDir: getLegacyDir(),
|
|
114
|
+
legacyExists: legacyDirExists(),
|
|
115
|
+
xdgConfigHome: process.env[exports.XDG_CONFIG_HOME_ENV],
|
|
116
|
+
xdgCacheHome: process.env[exports.XDG_CACHE_HOME_ENV],
|
|
117
|
+
platform: process.platform,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const paths_1 = require("./paths");
|
|
10
|
+
(0, vitest_1.describe)('Path Resolution', () => {
|
|
11
|
+
const testHome = '/test/home';
|
|
12
|
+
(0, vitest_1.describe)('getConfigDir', () => {
|
|
13
|
+
(0, vitest_1.test)('uses XDG_CONFIG_HOME when set', () => {
|
|
14
|
+
vitest_1.vi.stubEnv('XDG_CONFIG_HOME', '/custom/config');
|
|
15
|
+
(0, vitest_1.expect)((0, paths_1.getConfigDir)(testHome)).toBe('/custom/config/kanban-ai');
|
|
16
|
+
vitest_1.vi.unstubAllEnvs();
|
|
17
|
+
});
|
|
18
|
+
(0, vitest_1.test)('falls back to ~/.config when XDG_CONFIG_HOME not set', () => {
|
|
19
|
+
vitest_1.vi.stubEnv('XDG_CONFIG_HOME', undefined);
|
|
20
|
+
(0, vitest_1.expect)((0, paths_1.getConfigDir)(testHome)).toBe('/test/home/.config/kanban-ai');
|
|
21
|
+
vitest_1.vi.unstubAllEnvs();
|
|
22
|
+
});
|
|
23
|
+
(0, vitest_1.test)('uses provided home directory', () => {
|
|
24
|
+
vitest_1.vi.stubEnv('XDG_CONFIG_HOME', undefined);
|
|
25
|
+
(0, vitest_1.expect)((0, paths_1.getConfigDir)('/another/home')).toBe('/another/home/.config/kanban-ai');
|
|
26
|
+
vitest_1.vi.unstubAllEnvs();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.describe)('getCacheDir', () => {
|
|
30
|
+
(0, vitest_1.test)('uses XDG_CACHE_HOME when set', () => {
|
|
31
|
+
vitest_1.vi.stubEnv('XDG_CACHE_HOME', '/custom/cache');
|
|
32
|
+
(0, vitest_1.expect)((0, paths_1.getCacheDir)(testHome)).toBe('/custom/cache/kanban-ai');
|
|
33
|
+
vitest_1.vi.unstubAllEnvs();
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.test)('falls back to ~/.cache when XDG_CACHE_HOME not set', () => {
|
|
36
|
+
vitest_1.vi.stubEnv('XDG_CACHE_HOME', undefined);
|
|
37
|
+
(0, vitest_1.expect)((0, paths_1.getCacheDir)(testHome)).toBe('/test/home/.cache/kanban-ai');
|
|
38
|
+
vitest_1.vi.unstubAllEnvs();
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.test)('uses provided home directory', () => {
|
|
41
|
+
vitest_1.vi.stubEnv('XDG_CACHE_HOME', undefined);
|
|
42
|
+
(0, vitest_1.expect)((0, paths_1.getCacheDir)('/another/home')).toBe('/another/home/.cache/kanban-ai');
|
|
43
|
+
vitest_1.vi.unstubAllEnvs();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
(0, vitest_1.describe)('getLegacyDir', () => {
|
|
47
|
+
(0, vitest_1.test)('returns ~/.kanbanAI', () => {
|
|
48
|
+
(0, vitest_1.expect)((0, paths_1.getLegacyDir)(testHome)).toBe('/test/home/.kanbanAI');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
(0, vitest_1.describe)('legacyDirExists', () => {
|
|
52
|
+
(0, vitest_1.test)('returns false when legacy directory does not exist', () => {
|
|
53
|
+
vitest_1.vi.stubEnv('HOME', '/nonexistent');
|
|
54
|
+
(0, vitest_1.expect)((0, paths_1.legacyDirExists)()).toBe(false);
|
|
55
|
+
vitest_1.vi.unstubAllEnvs();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
(0, vitest_1.describe)('getConfigSubdirPath', () => {
|
|
59
|
+
(0, vitest_1.test)('creates path for config subdirectory', () => {
|
|
60
|
+
vitest_1.vi.stubEnv('XDG_CONFIG_HOME', undefined);
|
|
61
|
+
(0, vitest_1.expect)((0, paths_1.getConfigSubdirPath)('test')).toBe(node_path_1.default.join(node_os_1.default.homedir(), '.config', 'kanban-ai', 'test'));
|
|
62
|
+
vitest_1.vi.unstubAllEnvs();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
(0, vitest_1.describe)('getCacheSubdirPath', () => {
|
|
66
|
+
(0, vitest_1.test)('creates path for cache subdirectory', () => {
|
|
67
|
+
vitest_1.vi.stubEnv('XDG_CACHE_HOME', undefined);
|
|
68
|
+
(0, vitest_1.expect)((0, paths_1.getCacheSubdirPath)('test')).toBe(node_path_1.default.join(node_os_1.default.homedir(), '.cache', 'kanban-ai', 'test'));
|
|
69
|
+
vitest_1.vi.unstubAllEnvs();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
(0, vitest_1.describe)('getPathInfo', () => {
|
|
73
|
+
(0, vitest_1.test)('returns comprehensive path information', () => {
|
|
74
|
+
vitest_1.vi.stubEnv('XDG_CONFIG_HOME', undefined);
|
|
75
|
+
vitest_1.vi.stubEnv('XDG_CACHE_HOME', undefined);
|
|
76
|
+
const info = (0, paths_1.getPathInfo)();
|
|
77
|
+
(0, vitest_1.expect)(info).toHaveProperty('configDir');
|
|
78
|
+
(0, vitest_1.expect)(info).toHaveProperty('cacheDir');
|
|
79
|
+
(0, vitest_1.expect)(info).toHaveProperty('legacyDir');
|
|
80
|
+
(0, vitest_1.expect)(info).toHaveProperty('legacyExists');
|
|
81
|
+
(0, vitest_1.expect)(info).toHaveProperty('xdgConfigHome');
|
|
82
|
+
(0, vitest_1.expect)(info).toHaveProperty('xdgCacheHome');
|
|
83
|
+
(0, vitest_1.expect)(info).toHaveProperty('platform');
|
|
84
|
+
vitest_1.vi.unstubAllEnvs();
|
|
85
|
+
});
|
|
86
|
+
(0, vitest_1.test)('includes XDG environment variables when set', () => {
|
|
87
|
+
vitest_1.vi.stubEnv('XDG_CONFIG_HOME', '/custom/config');
|
|
88
|
+
vitest_1.vi.stubEnv('XDG_CACHE_HOME', '/custom/cache');
|
|
89
|
+
const info = (0, paths_1.getPathInfo)();
|
|
90
|
+
(0, vitest_1.expect)(info.xdgConfigHome).toBe('/custom/config');
|
|
91
|
+
(0, vitest_1.expect)(info.xdgCacheHome).toBe('/custom/cache');
|
|
92
|
+
vitest_1.vi.unstubAllEnvs();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
(0, vitest_1.describe)('Windows Support', () => {
|
|
96
|
+
(0, vitest_1.test)('uses APPDATA for config on Windows when XDG not set', () => {
|
|
97
|
+
vitest_1.vi.stubEnv('XDG_CONFIG_HOME', undefined);
|
|
98
|
+
vitest_1.vi.stubEnv('APPDATA', 'C:\\Users\\test\\AppData\\Roaming');
|
|
99
|
+
// Mock platform detection
|
|
100
|
+
const originalPlatform = process.platform;
|
|
101
|
+
Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
|
|
102
|
+
const result = (0, paths_1.getConfigDir)('C:\\Users\\test');
|
|
103
|
+
// On Linux, path.join normalizes to forward slashes, but the path structure is correct
|
|
104
|
+
(0, vitest_1.expect)(result.toLowerCase()).toContain('appdata\\roaming'.toLowerCase());
|
|
105
|
+
(0, vitest_1.expect)(result).toContain('kanban-ai');
|
|
106
|
+
// Restore platform
|
|
107
|
+
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
108
|
+
vitest_1.vi.unstubAllEnvs();
|
|
109
|
+
});
|
|
110
|
+
(0, vitest_1.test)('uses LOCALAPPDATA for cache on Windows when XDG not set', () => {
|
|
111
|
+
vitest_1.vi.stubEnv('XDG_CACHE_HOME', undefined);
|
|
112
|
+
vitest_1.vi.stubEnv('LOCALAPPDATA', 'C:\\Users\\test\\AppData\\Local');
|
|
113
|
+
// Mock platform detection
|
|
114
|
+
const originalPlatform = process.platform;
|
|
115
|
+
Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
|
|
116
|
+
const result = (0, paths_1.getCacheDir)('C:\\Users\\test');
|
|
117
|
+
(0, vitest_1.expect)(result.toLowerCase()).toContain('appdata\\local'.toLowerCase());
|
|
118
|
+
(0, vitest_1.expect)(result).toContain('kanban-ai');
|
|
119
|
+
// Restore platform
|
|
120
|
+
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
121
|
+
vitest_1.vi.unstubAllEnvs();
|
|
122
|
+
});
|
|
123
|
+
(0, vitest_1.test)('falls back to AppData\\Roaming when APPDATA not set on Windows', () => {
|
|
124
|
+
vitest_1.vi.stubEnv('XDG_CONFIG_HOME', undefined);
|
|
125
|
+
vitest_1.vi.stubEnv('APPDATA', undefined);
|
|
126
|
+
// Mock platform detection
|
|
127
|
+
const originalPlatform = process.platform;
|
|
128
|
+
Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
|
|
129
|
+
const result = (0, paths_1.getConfigDir)('C:\\Users\\test');
|
|
130
|
+
// On Linux, path.join normalizes to forward slashes, so check for both with/without separator
|
|
131
|
+
const normalizedResult = result.toLowerCase().replace(/\\/g, '/');
|
|
132
|
+
(0, vitest_1.expect)(normalizedResult).toContain('appdata/roaming');
|
|
133
|
+
(0, vitest_1.expect)(result).toContain('kanban-ai');
|
|
134
|
+
// Restore platform
|
|
135
|
+
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
136
|
+
vitest_1.vi.unstubAllEnvs();
|
|
137
|
+
});
|
|
138
|
+
(0, vitest_1.test)('falls back to AppData\\Local when LOCALAPPDATA not set on Windows', () => {
|
|
139
|
+
vitest_1.vi.stubEnv('XDG_CACHE_HOME', undefined);
|
|
140
|
+
vitest_1.vi.stubEnv('LOCALAPPDATA', undefined);
|
|
141
|
+
// Mock platform detection
|
|
142
|
+
const originalPlatform = process.platform;
|
|
143
|
+
Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
|
|
144
|
+
const result = (0, paths_1.getCacheDir)('C:\\Users\\test');
|
|
145
|
+
// On Linux, path.join normalizes to forward slashes, so check for both with/without separator
|
|
146
|
+
const normalizedResult = result.toLowerCase().replace(/\\/g, '/');
|
|
147
|
+
(0, vitest_1.expect)(normalizedResult).toContain('appdata/local');
|
|
148
|
+
(0, vitest_1.expect)(result).toContain('kanban-ai');
|
|
149
|
+
// Restore platform
|
|
150
|
+
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
151
|
+
vitest_1.vi.unstubAllEnvs();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
package/dist/updates.test.js
CHANGED