@garyr/pt-cli 0.32.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/commands/configCommand.js +2 -2
- package/dist/config.js +33 -12
- package/dist/postconfig.js +49 -6
- package/dist/remote.js +33 -1
- package/dist/safety.js +250 -0
- package/doc/configuration.md +11 -0
- package/doc/security.md +132 -0
- package/doc/testing.md +21 -1
- package/doc/usage.md +28 -14
- package/package.json +4 -4
- package/skills/agency-pt-operator/SKILL.md +104 -15
- package/src/commands/configCommand.ts +2 -2
- package/src/config.ts +38 -12
- package/src/postconfig.ts +66 -5
- package/src/remote.ts +40 -1
- package/src/safety.ts +299 -0
- package/tests/config-u.ts +4 -0
- package/tests/config-utils.test.ts +11 -11
- package/tests/config.test.ts +111 -96
- package/tests/init.test.ts +1 -1
- package/tests/learn.test.ts +3 -3
- package/test-direct-template.json +0 -24
package/tests/config.test.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import { test,
|
|
1
|
+
import { test, after } from 'node:test';
|
|
2
2
|
import assert from 'node:assert';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import os from 'os';
|
|
6
5
|
|
|
7
6
|
// Force a temporary home directory for testing before importing anything from the CLI
|
|
8
7
|
const testHome = path.join(process.cwd(), '.test-home-config');
|
|
9
8
|
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
os.homedir = () => testHome;
|
|
9
|
+
// Set HOME environment variable before importing (needed for dynamic getters)
|
|
10
|
+
process.env.HOME = testHome;
|
|
13
11
|
|
|
14
|
-
import { normalizeVariable, saveConfig, loadConfig, PtConfig,
|
|
12
|
+
import { normalizeVariable, saveConfig, loadConfig, PtConfig, getConfigPath, getHomeDir } from '../src/config.js';
|
|
15
13
|
|
|
16
14
|
test('normalizeVariable key ordering', () => {
|
|
17
15
|
const variableInput = {
|
|
@@ -32,15 +30,15 @@ test('normalizeVariable key ordering', () => {
|
|
|
32
30
|
test('saveConfig and loadConfig roundtrip', () => {
|
|
33
31
|
// Save the current config to restore later
|
|
34
32
|
let savedConfig: PtConfig | null = null;
|
|
35
|
-
if (fs.existsSync(
|
|
33
|
+
if (fs.existsSync(getConfigPath())) {
|
|
36
34
|
savedConfig = loadConfig();
|
|
37
35
|
}
|
|
38
36
|
|
|
39
37
|
// Clean up any existing test files
|
|
40
|
-
if (fs.existsSync(
|
|
41
|
-
fs.unlinkSync(
|
|
38
|
+
if (fs.existsSync(getConfigPath())) {
|
|
39
|
+
fs.unlinkSync(getConfigPath());
|
|
42
40
|
}
|
|
43
|
-
const backupPath =
|
|
41
|
+
const backupPath = getConfigPath() + '.bak';
|
|
44
42
|
if (fs.existsSync(backupPath)) {
|
|
45
43
|
fs.unlinkSync(backupPath);
|
|
46
44
|
}
|
|
@@ -68,11 +66,11 @@ test('saveConfig and loadConfig roundtrip', () => {
|
|
|
68
66
|
// Save the config
|
|
69
67
|
saveConfig(testConfig);
|
|
70
68
|
|
|
71
|
-
// Assert
|
|
72
|
-
assert.ok(fs.existsSync(
|
|
69
|
+
// Assert getConfigPath() exists and has been created
|
|
70
|
+
assert.ok(fs.existsSync(getConfigPath()), 'Config file should be created');
|
|
73
71
|
|
|
74
72
|
// Verify key order in YAML string
|
|
75
|
-
const yamlContent = fs.readFileSync(
|
|
73
|
+
const yamlContent = fs.readFileSync(getConfigPath(), 'utf-8');
|
|
76
74
|
assert.ok(yamlContent.includes('name: myVar'), 'Should contain myVar variable');
|
|
77
75
|
|
|
78
76
|
// Load the config back
|
|
@@ -96,8 +94,8 @@ test('saveConfig and loadConfig roundtrip', () => {
|
|
|
96
94
|
assert.ok(backupContent.includes("version: 1.0.0") || backupContent.includes("version: '1.0.0'"), 'Backup should contain previous version');
|
|
97
95
|
|
|
98
96
|
// Clean up
|
|
99
|
-
if (fs.existsSync(
|
|
100
|
-
fs.unlinkSync(
|
|
97
|
+
if (fs.existsSync(getConfigPath())) {
|
|
98
|
+
fs.unlinkSync(getConfigPath());
|
|
101
99
|
}
|
|
102
100
|
if (fs.existsSync(backupPath)) {
|
|
103
101
|
fs.unlinkSync(backupPath);
|
|
@@ -109,7 +107,7 @@ test('saveConfig and loadConfig roundtrip', () => {
|
|
|
109
107
|
}
|
|
110
108
|
|
|
111
109
|
if (fs.existsSync(testHome)) {
|
|
112
|
-
fs.
|
|
110
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
113
111
|
}
|
|
114
112
|
});
|
|
115
113
|
|
|
@@ -148,15 +146,15 @@ test('normalizeVariable with all fields', () => {
|
|
|
148
146
|
test('saveConfig creates backup on overwrite', () => {
|
|
149
147
|
// Save the current config to restore later
|
|
150
148
|
let savedConfig: PtConfig | null = null;
|
|
151
|
-
if (fs.existsSync(
|
|
149
|
+
if (fs.existsSync(getConfigPath())) {
|
|
152
150
|
savedConfig = loadConfig();
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
// Clean up any existing test files
|
|
156
|
-
if (fs.existsSync(
|
|
157
|
-
fs.unlinkSync(
|
|
154
|
+
if (fs.existsSync(getConfigPath())) {
|
|
155
|
+
fs.unlinkSync(getConfigPath());
|
|
158
156
|
}
|
|
159
|
-
const backupPath =
|
|
157
|
+
const backupPath = getConfigPath() + '.bak';
|
|
160
158
|
if (fs.existsSync(backupPath)) {
|
|
161
159
|
fs.unlinkSync(backupPath);
|
|
162
160
|
}
|
|
@@ -172,7 +170,7 @@ test('saveConfig creates backup on overwrite', () => {
|
|
|
172
170
|
|
|
173
171
|
// Save first config
|
|
174
172
|
saveConfig(config1);
|
|
175
|
-
assert.ok(fs.existsSync(
|
|
173
|
+
assert.ok(fs.existsSync(getConfigPath()), 'Config file should be created');
|
|
176
174
|
|
|
177
175
|
// Save second config (should create backup)
|
|
178
176
|
saveConfig(config2);
|
|
@@ -183,8 +181,8 @@ test('saveConfig creates backup on overwrite', () => {
|
|
|
183
181
|
assert.ok(backupContent.includes("version: 1.0.0") || backupContent.includes("version: '1.0.0'"), 'Backup should contain previous version');
|
|
184
182
|
|
|
185
183
|
// Clean up
|
|
186
|
-
if (fs.existsSync(
|
|
187
|
-
fs.unlinkSync(
|
|
184
|
+
if (fs.existsSync(getConfigPath())) {
|
|
185
|
+
fs.unlinkSync(getConfigPath());
|
|
188
186
|
}
|
|
189
187
|
if (fs.existsSync(backupPath)) {
|
|
190
188
|
fs.unlinkSync(backupPath);
|
|
@@ -196,22 +194,22 @@ test('saveConfig creates backup on overwrite', () => {
|
|
|
196
194
|
}
|
|
197
195
|
|
|
198
196
|
if (fs.existsSync(testHome)) {
|
|
199
|
-
fs.
|
|
197
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
200
198
|
}
|
|
201
199
|
});
|
|
202
200
|
|
|
203
201
|
test('saveConfig atomic write behavior', () => {
|
|
204
202
|
// Save the current config to restore later
|
|
205
203
|
let savedConfig: PtConfig | null = null;
|
|
206
|
-
if (fs.existsSync(
|
|
204
|
+
if (fs.existsSync(getConfigPath())) {
|
|
207
205
|
savedConfig = loadConfig();
|
|
208
206
|
}
|
|
209
207
|
|
|
210
208
|
// Clean up any existing test files
|
|
211
|
-
if (fs.existsSync(
|
|
212
|
-
fs.unlinkSync(
|
|
209
|
+
if (fs.existsSync(getConfigPath())) {
|
|
210
|
+
fs.unlinkSync(getConfigPath());
|
|
213
211
|
}
|
|
214
|
-
const backupPath =
|
|
212
|
+
const backupPath = getConfigPath() + '.bak';
|
|
215
213
|
if (fs.existsSync(backupPath)) {
|
|
216
214
|
fs.unlinkSync(backupPath);
|
|
217
215
|
}
|
|
@@ -225,15 +223,15 @@ test('saveConfig atomic write behavior', () => {
|
|
|
225
223
|
saveConfig(config);
|
|
226
224
|
|
|
227
225
|
// Verify config exists
|
|
228
|
-
assert.ok(fs.existsSync(
|
|
226
|
+
assert.ok(fs.existsSync(getConfigPath()), 'Config file should be created');
|
|
229
227
|
|
|
230
228
|
// Verify no temp file remains
|
|
231
|
-
const tempPath =
|
|
229
|
+
const tempPath = getConfigPath() + '.tmp';
|
|
232
230
|
assert.ok(!fs.existsSync(tempPath), 'Temp file should not remain');
|
|
233
231
|
|
|
234
232
|
// Clean up
|
|
235
|
-
if (fs.existsSync(
|
|
236
|
-
fs.unlinkSync(
|
|
233
|
+
if (fs.existsSync(getConfigPath())) {
|
|
234
|
+
fs.unlinkSync(getConfigPath());
|
|
237
235
|
}
|
|
238
236
|
if (fs.existsSync(backupPath)) {
|
|
239
237
|
fs.unlinkSync(backupPath);
|
|
@@ -245,22 +243,22 @@ test('saveConfig atomic write behavior', () => {
|
|
|
245
243
|
}
|
|
246
244
|
|
|
247
245
|
if (fs.existsSync(testHome)) {
|
|
248
|
-
fs.
|
|
246
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
249
247
|
}
|
|
250
248
|
});
|
|
251
249
|
|
|
252
250
|
test('loadConfig returns default config when file missing', () => {
|
|
253
251
|
// Save the current config to restore later
|
|
254
252
|
let savedConfig: PtConfig | null = null;
|
|
255
|
-
if (fs.existsSync(
|
|
253
|
+
if (fs.existsSync(getConfigPath())) {
|
|
256
254
|
savedConfig = loadConfig();
|
|
257
255
|
}
|
|
258
256
|
|
|
259
257
|
// Clean up any existing test files
|
|
260
|
-
if (fs.existsSync(
|
|
261
|
-
fs.unlinkSync(
|
|
258
|
+
if (fs.existsSync(getConfigPath())) {
|
|
259
|
+
fs.unlinkSync(getConfigPath());
|
|
262
260
|
}
|
|
263
|
-
const backupPath =
|
|
261
|
+
const backupPath = getConfigPath() + '.bak';
|
|
264
262
|
if (fs.existsSync(backupPath)) {
|
|
265
263
|
fs.unlinkSync(backupPath);
|
|
266
264
|
}
|
|
@@ -275,7 +273,7 @@ test('loadConfig returns default config when file missing', () => {
|
|
|
275
273
|
|
|
276
274
|
// Clean up
|
|
277
275
|
if (fs.existsSync(testHome)) {
|
|
278
|
-
fs.
|
|
276
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
279
277
|
}
|
|
280
278
|
|
|
281
279
|
// Restore the original config if it existed
|
|
@@ -287,15 +285,15 @@ test('loadConfig returns default config when file missing', () => {
|
|
|
287
285
|
test('saveConfig with variables normalizes key order', () => {
|
|
288
286
|
// Save the current config to restore later
|
|
289
287
|
let savedConfig: PtConfig | null = null;
|
|
290
|
-
if (fs.existsSync(
|
|
288
|
+
if (fs.existsSync(getConfigPath())) {
|
|
291
289
|
savedConfig = loadConfig();
|
|
292
290
|
}
|
|
293
291
|
|
|
294
292
|
// Clean up any existing test files
|
|
295
|
-
if (fs.existsSync(
|
|
296
|
-
fs.unlinkSync(
|
|
293
|
+
if (fs.existsSync(getConfigPath())) {
|
|
294
|
+
fs.unlinkSync(getConfigPath());
|
|
297
295
|
}
|
|
298
|
-
const backupPath =
|
|
296
|
+
const backupPath = getConfigPath() + '.bak';
|
|
299
297
|
if (fs.existsSync(backupPath)) {
|
|
300
298
|
fs.unlinkSync(backupPath);
|
|
301
299
|
}
|
|
@@ -336,8 +334,8 @@ test('saveConfig with variables normalizes key order', () => {
|
|
|
336
334
|
assert.strictEqual(vars[1].name, 'var2', 'Second variable name should be var2');
|
|
337
335
|
|
|
338
336
|
// Clean up
|
|
339
|
-
if (fs.existsSync(
|
|
340
|
-
fs.unlinkSync(
|
|
337
|
+
if (fs.existsSync(getConfigPath())) {
|
|
338
|
+
fs.unlinkSync(getConfigPath());
|
|
341
339
|
}
|
|
342
340
|
if (fs.existsSync(backupPath)) {
|
|
343
341
|
fs.unlinkSync(backupPath);
|
|
@@ -349,28 +347,33 @@ test('saveConfig with variables normalizes key order', () => {
|
|
|
349
347
|
}
|
|
350
348
|
|
|
351
349
|
if (fs.existsSync(testHome)) {
|
|
352
|
-
fs.
|
|
350
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
353
351
|
}
|
|
354
352
|
});
|
|
355
353
|
|
|
356
354
|
test('saveConfig with empty config file', () => {
|
|
357
355
|
// Save the current config to restore later
|
|
358
356
|
let savedConfig: PtConfig | null = null;
|
|
359
|
-
if (fs.existsSync(
|
|
357
|
+
if (fs.existsSync(getConfigPath())) {
|
|
360
358
|
savedConfig = loadConfig();
|
|
361
359
|
}
|
|
362
360
|
|
|
363
361
|
// Clean up any existing test files
|
|
364
|
-
if (fs.existsSync(
|
|
365
|
-
fs.unlinkSync(
|
|
362
|
+
if (fs.existsSync(getConfigPath())) {
|
|
363
|
+
fs.unlinkSync(getConfigPath());
|
|
366
364
|
}
|
|
367
|
-
const backupPath =
|
|
365
|
+
const backupPath = getConfigPath() + '.bak';
|
|
368
366
|
if (fs.existsSync(backupPath)) {
|
|
369
367
|
fs.unlinkSync(backupPath);
|
|
370
368
|
}
|
|
371
369
|
|
|
370
|
+
// Ensure the config directory exists
|
|
371
|
+
if (!fs.existsSync(getHomeDir())) {
|
|
372
|
+
fs.mkdirSync(getHomeDir(), { recursive: true });
|
|
373
|
+
}
|
|
374
|
+
|
|
372
375
|
// Create empty config file
|
|
373
|
-
fs.writeFileSync(
|
|
376
|
+
fs.writeFileSync(getConfigPath(), '');
|
|
374
377
|
|
|
375
378
|
// loadConfig calls process.exit(1) on error, so we need to mock it
|
|
376
379
|
// to prevent the test runner from dying
|
|
@@ -394,8 +397,8 @@ test('saveConfig with empty config file', () => {
|
|
|
394
397
|
}
|
|
395
398
|
|
|
396
399
|
// Clean up
|
|
397
|
-
if (fs.existsSync(
|
|
398
|
-
fs.unlinkSync(
|
|
400
|
+
if (fs.existsSync(getConfigPath())) {
|
|
401
|
+
fs.unlinkSync(getConfigPath());
|
|
399
402
|
}
|
|
400
403
|
if (fs.existsSync(backupPath)) {
|
|
401
404
|
fs.unlinkSync(backupPath);
|
|
@@ -407,7 +410,7 @@ test('saveConfig with empty config file', () => {
|
|
|
407
410
|
}
|
|
408
411
|
|
|
409
412
|
if (fs.existsSync(testHome)) {
|
|
410
|
-
fs.
|
|
413
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
411
414
|
}
|
|
412
415
|
});
|
|
413
416
|
|
|
@@ -429,15 +432,15 @@ test('normalizeVariable preserves field order', () => {
|
|
|
429
432
|
test('saveConfig handles multiple templates', () => {
|
|
430
433
|
// Save the current config to restore later
|
|
431
434
|
let savedConfig: PtConfig | null = null;
|
|
432
|
-
if (fs.existsSync(
|
|
435
|
+
if (fs.existsSync(getConfigPath())) {
|
|
433
436
|
savedConfig = loadConfig();
|
|
434
437
|
}
|
|
435
438
|
|
|
436
439
|
// Clean up any existing test files
|
|
437
|
-
if (fs.existsSync(
|
|
438
|
-
fs.unlinkSync(
|
|
440
|
+
if (fs.existsSync(getConfigPath())) {
|
|
441
|
+
fs.unlinkSync(getConfigPath());
|
|
439
442
|
}
|
|
440
|
-
const backupPath =
|
|
443
|
+
const backupPath = getConfigPath() + '.bak';
|
|
441
444
|
if (fs.existsSync(backupPath)) {
|
|
442
445
|
fs.unlinkSync(backupPath);
|
|
443
446
|
}
|
|
@@ -466,8 +469,8 @@ test('saveConfig handles multiple templates', () => {
|
|
|
466
469
|
assert.strictEqual(loaded.templates['template2'].description, 'Template 2');
|
|
467
470
|
|
|
468
471
|
// Clean up
|
|
469
|
-
if (fs.existsSync(
|
|
470
|
-
fs.unlinkSync(
|
|
472
|
+
if (fs.existsSync(getConfigPath())) {
|
|
473
|
+
fs.unlinkSync(getConfigPath());
|
|
471
474
|
}
|
|
472
475
|
if (fs.existsSync(backupPath)) {
|
|
473
476
|
fs.unlinkSync(backupPath);
|
|
@@ -479,22 +482,22 @@ test('saveConfig handles multiple templates', () => {
|
|
|
479
482
|
}
|
|
480
483
|
|
|
481
484
|
if (fs.existsSync(testHome)) {
|
|
482
|
-
fs.
|
|
485
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
483
486
|
}
|
|
484
487
|
});
|
|
485
488
|
|
|
486
489
|
test('saveConfig handles templates with variables', () => {
|
|
487
490
|
// Save the current config to restore later
|
|
488
491
|
let savedConfig: PtConfig | null = null;
|
|
489
|
-
if (fs.existsSync(
|
|
492
|
+
if (fs.existsSync(getConfigPath())) {
|
|
490
493
|
savedConfig = loadConfig();
|
|
491
494
|
}
|
|
492
495
|
|
|
493
496
|
// Clean up any existing test files
|
|
494
|
-
if (fs.existsSync(
|
|
495
|
-
fs.unlinkSync(
|
|
497
|
+
if (fs.existsSync(getConfigPath())) {
|
|
498
|
+
fs.unlinkSync(getConfigPath());
|
|
496
499
|
}
|
|
497
|
-
const backupPath =
|
|
500
|
+
const backupPath = getConfigPath() + '.bak';
|
|
498
501
|
if (fs.existsSync(backupPath)) {
|
|
499
502
|
fs.unlinkSync(backupPath);
|
|
500
503
|
}
|
|
@@ -532,8 +535,8 @@ test('saveConfig handles templates with variables', () => {
|
|
|
532
535
|
assert.strictEqual(template.variables?.[0].required, true, 'Variable should be required');
|
|
533
536
|
|
|
534
537
|
// Clean up
|
|
535
|
-
if (fs.existsSync(
|
|
536
|
-
fs.unlinkSync(
|
|
538
|
+
if (fs.existsSync(getConfigPath())) {
|
|
539
|
+
fs.unlinkSync(getConfigPath());
|
|
537
540
|
}
|
|
538
541
|
if (fs.existsSync(backupPath)) {
|
|
539
542
|
fs.unlinkSync(backupPath);
|
|
@@ -545,26 +548,31 @@ test('saveConfig handles templates with variables', () => {
|
|
|
545
548
|
}
|
|
546
549
|
|
|
547
550
|
if (fs.existsSync(testHome)) {
|
|
548
|
-
fs.
|
|
551
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
549
552
|
}
|
|
550
553
|
});
|
|
551
554
|
|
|
552
555
|
test('loadConfig handles migration from v2.0', () => {
|
|
553
556
|
// Save the current config to restore later
|
|
554
557
|
let savedConfig: PtConfig | null = null;
|
|
555
|
-
if (fs.existsSync(
|
|
558
|
+
if (fs.existsSync(getConfigPath())) {
|
|
556
559
|
savedConfig = loadConfig();
|
|
557
560
|
}
|
|
558
561
|
|
|
559
562
|
// Clean up any existing test files
|
|
560
|
-
if (fs.existsSync(
|
|
561
|
-
fs.unlinkSync(
|
|
563
|
+
if (fs.existsSync(getConfigPath())) {
|
|
564
|
+
fs.unlinkSync(getConfigPath());
|
|
562
565
|
}
|
|
563
|
-
const backupPath =
|
|
566
|
+
const backupPath = getConfigPath() + '.bak';
|
|
564
567
|
if (fs.existsSync(backupPath)) {
|
|
565
568
|
fs.unlinkSync(backupPath);
|
|
566
569
|
}
|
|
567
570
|
|
|
571
|
+
// Ensure the config directory exists
|
|
572
|
+
if (!fs.existsSync(getHomeDir())) {
|
|
573
|
+
fs.mkdirSync(getHomeDir(), { recursive: true });
|
|
574
|
+
}
|
|
575
|
+
|
|
568
576
|
// Create a v2.0 config
|
|
569
577
|
const v2Config = {
|
|
570
578
|
version: '2.0',
|
|
@@ -577,7 +585,7 @@ test('loadConfig handles migration from v2.0', () => {
|
|
|
577
585
|
}
|
|
578
586
|
};
|
|
579
587
|
|
|
580
|
-
fs.writeFileSync(
|
|
588
|
+
fs.writeFileSync(getConfigPath(), JSON.stringify(v2Config));
|
|
581
589
|
|
|
582
590
|
// Load config - should migrate to v3.0
|
|
583
591
|
const config = loadConfig();
|
|
@@ -588,8 +596,8 @@ test('loadConfig handles migration from v2.0', () => {
|
|
|
588
596
|
assert.ok(!config.templates['test-template'].type, 'Type should be removed');
|
|
589
597
|
|
|
590
598
|
// Clean up
|
|
591
|
-
if (fs.existsSync(
|
|
592
|
-
fs.unlinkSync(
|
|
599
|
+
if (fs.existsSync(getConfigPath())) {
|
|
600
|
+
fs.unlinkSync(getConfigPath());
|
|
593
601
|
}
|
|
594
602
|
if (fs.existsSync(backupPath)) {
|
|
595
603
|
fs.unlinkSync(backupPath);
|
|
@@ -601,26 +609,31 @@ test('loadConfig handles migration from v2.0', () => {
|
|
|
601
609
|
}
|
|
602
610
|
|
|
603
611
|
if (fs.existsSync(testHome)) {
|
|
604
|
-
fs.
|
|
612
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
605
613
|
}
|
|
606
614
|
});
|
|
607
615
|
|
|
608
616
|
test('loadConfig handles migration from v2.0 with global_post_config', () => {
|
|
609
617
|
// Save the current config to restore later
|
|
610
618
|
let savedConfig: PtConfig | null = null;
|
|
611
|
-
if (fs.existsSync(
|
|
619
|
+
if (fs.existsSync(getConfigPath())) {
|
|
612
620
|
savedConfig = loadConfig();
|
|
613
621
|
}
|
|
614
622
|
|
|
615
623
|
// Clean up any existing test files
|
|
616
|
-
if (fs.existsSync(
|
|
617
|
-
fs.unlinkSync(
|
|
624
|
+
if (fs.existsSync(getConfigPath())) {
|
|
625
|
+
fs.unlinkSync(getConfigPath());
|
|
618
626
|
}
|
|
619
|
-
const backupPath =
|
|
627
|
+
const backupPath = getConfigPath() + '.bak';
|
|
620
628
|
if (fs.existsSync(backupPath)) {
|
|
621
629
|
fs.unlinkSync(backupPath);
|
|
622
630
|
}
|
|
623
631
|
|
|
632
|
+
// Ensure the config directory exists
|
|
633
|
+
if (!fs.existsSync(getHomeDir())) {
|
|
634
|
+
fs.mkdirSync(getHomeDir(), { recursive: true });
|
|
635
|
+
}
|
|
636
|
+
|
|
624
637
|
// Create a v2.0 config with global_post_config
|
|
625
638
|
const v2Config = {
|
|
626
639
|
version: '2.0',
|
|
@@ -633,7 +646,7 @@ test('loadConfig handles migration from v2.0 with global_post_config', () => {
|
|
|
633
646
|
]
|
|
634
647
|
};
|
|
635
648
|
|
|
636
|
-
fs.writeFileSync(
|
|
649
|
+
fs.writeFileSync(getConfigPath(), JSON.stringify(v2Config));
|
|
637
650
|
|
|
638
651
|
// Load config - should migrate to v3.0
|
|
639
652
|
const config = loadConfig();
|
|
@@ -649,8 +662,8 @@ test('loadConfig handles migration from v2.0 with global_post_config', () => {
|
|
|
649
662
|
assert.ok(!config.global_post_config, 'global_post_config should be removed');
|
|
650
663
|
|
|
651
664
|
// Clean up
|
|
652
|
-
if (fs.existsSync(
|
|
653
|
-
fs.unlinkSync(
|
|
665
|
+
if (fs.existsSync(getConfigPath())) {
|
|
666
|
+
fs.unlinkSync(getConfigPath());
|
|
654
667
|
}
|
|
655
668
|
if (fs.existsSync(backupPath)) {
|
|
656
669
|
fs.unlinkSync(backupPath);
|
|
@@ -662,26 +675,31 @@ test('loadConfig handles migration from v2.0 with global_post_config', () => {
|
|
|
662
675
|
}
|
|
663
676
|
|
|
664
677
|
if (fs.existsSync(testHome)) {
|
|
665
|
-
fs.
|
|
678
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
666
679
|
}
|
|
667
680
|
});
|
|
668
681
|
|
|
669
682
|
test('loadConfig handles migration from v2.0 with variables', () => {
|
|
670
683
|
// Save the current config to restore later
|
|
671
684
|
let savedConfig: PtConfig | null = null;
|
|
672
|
-
if (fs.existsSync(
|
|
685
|
+
if (fs.existsSync(getConfigPath())) {
|
|
673
686
|
savedConfig = loadConfig();
|
|
674
687
|
}
|
|
675
688
|
|
|
676
689
|
// Clean up any existing test files
|
|
677
|
-
if (fs.existsSync(
|
|
678
|
-
fs.unlinkSync(
|
|
690
|
+
if (fs.existsSync(getConfigPath())) {
|
|
691
|
+
fs.unlinkSync(getConfigPath());
|
|
679
692
|
}
|
|
680
|
-
const backupPath =
|
|
693
|
+
const backupPath = getConfigPath() + '.bak';
|
|
681
694
|
if (fs.existsSync(backupPath)) {
|
|
682
695
|
fs.unlinkSync(backupPath);
|
|
683
696
|
}
|
|
684
697
|
|
|
698
|
+
// Ensure the config directory exists
|
|
699
|
+
if (!fs.existsSync(getHomeDir())) {
|
|
700
|
+
fs.mkdirSync(getHomeDir(), { recursive: true });
|
|
701
|
+
}
|
|
702
|
+
|
|
685
703
|
// Create a v2.0 config with variables as Record<string, string>
|
|
686
704
|
const v2Config = {
|
|
687
705
|
version: '2.0',
|
|
@@ -692,7 +710,7 @@ test('loadConfig handles migration from v2.0 with variables', () => {
|
|
|
692
710
|
}
|
|
693
711
|
};
|
|
694
712
|
|
|
695
|
-
fs.writeFileSync(
|
|
713
|
+
fs.writeFileSync(getConfigPath(), JSON.stringify(v2Config));
|
|
696
714
|
|
|
697
715
|
// Load config - should migrate to v3.0
|
|
698
716
|
const config = loadConfig();
|
|
@@ -706,8 +724,8 @@ test('loadConfig handles migration from v2.0 with variables', () => {
|
|
|
706
724
|
assert.strictEqual(config.variables[1].default, 'web', 'Second variable default should be web');
|
|
707
725
|
|
|
708
726
|
// Clean up
|
|
709
|
-
if (fs.existsSync(
|
|
710
|
-
fs.unlinkSync(
|
|
727
|
+
if (fs.existsSync(getConfigPath())) {
|
|
728
|
+
fs.unlinkSync(getConfigPath());
|
|
711
729
|
}
|
|
712
730
|
if (fs.existsSync(backupPath)) {
|
|
713
731
|
fs.unlinkSync(backupPath);
|
|
@@ -719,7 +737,7 @@ test('loadConfig handles migration from v2.0 with variables', () => {
|
|
|
719
737
|
}
|
|
720
738
|
|
|
721
739
|
if (fs.existsSync(testHome)) {
|
|
722
|
-
fs.
|
|
740
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
723
741
|
}
|
|
724
742
|
});
|
|
725
743
|
|
|
@@ -737,7 +755,7 @@ test('loadConfig handles existing config file', () => {
|
|
|
737
755
|
test('saveConfig preserves existing config when not deleting', () => {
|
|
738
756
|
// Save the current config to restore later
|
|
739
757
|
let savedConfig: PtConfig | null = null;
|
|
740
|
-
if (fs.existsSync(
|
|
758
|
+
if (fs.existsSync(getConfigPath())) {
|
|
741
759
|
savedConfig = loadConfig();
|
|
742
760
|
}
|
|
743
761
|
|
|
@@ -768,11 +786,8 @@ test('saveConfig preserves existing config when not deleting', () => {
|
|
|
768
786
|
|
|
769
787
|
// Cleanup: restore original os.homedir function and clean up test directory
|
|
770
788
|
after(() => {
|
|
771
|
-
// Restore original os.homedir function
|
|
772
|
-
os.homedir = originalHomedir;
|
|
773
|
-
|
|
774
789
|
// Clean up test home directory if it exists
|
|
775
790
|
if (fs.existsSync(testHome)) {
|
|
776
|
-
fs.
|
|
791
|
+
fs.rmSync(testHome, { recursive: true, force: true });
|
|
777
792
|
}
|
|
778
793
|
});
|
package/tests/init.test.ts
CHANGED
|
@@ -8,7 +8,7 @@ const testHome = path.join(process.cwd(), '.test-home-init');
|
|
|
8
8
|
process.env.HOME = testHome;
|
|
9
9
|
|
|
10
10
|
import { init } from '../src/commands/initCommand.js';
|
|
11
|
-
import { loadConfig, saveConfig, PtConfig,
|
|
11
|
+
import { loadConfig, saveConfig, PtConfig, getConfigPath } from '../src/config.js';
|
|
12
12
|
|
|
13
13
|
// Helper to clean up test directories
|
|
14
14
|
function cleanup(...paths: string[]) {
|
package/tests/learn.test.ts
CHANGED
|
@@ -9,7 +9,7 @@ const testHome = path.join(process.cwd(), '.test-home-learn');
|
|
|
9
9
|
process.env.HOME = testHome;
|
|
10
10
|
|
|
11
11
|
import { learn } from '../src/commands/learnCommand.js';
|
|
12
|
-
import { loadConfig, saveConfig, PtConfig,
|
|
12
|
+
import { loadConfig, saveConfig, PtConfig, getConfigPath } from '../src/config.js';
|
|
13
13
|
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
// Helpers
|
|
@@ -31,8 +31,8 @@ function rmrf(p: string) {
|
|
|
31
31
|
|
|
32
32
|
/** Ensure a clean test config state (no leftover config files). */
|
|
33
33
|
function cleanConfig() {
|
|
34
|
-
if (fs.existsSync(
|
|
35
|
-
const bak =
|
|
34
|
+
if (fs.existsSync(getConfigPath())) fs.unlinkSync(getConfigPath());
|
|
35
|
+
const bak = getConfigPath() + '.bak';
|
|
36
36
|
if (fs.existsSync(bak)) fs.unlinkSync(bak);
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "direct-json-test",
|
|
3
|
-
"description": "A mock template for direct JSON scaffolding test",
|
|
4
|
-
"folders": [
|
|
5
|
-
{
|
|
6
|
-
"name": "src",
|
|
7
|
-
"info": "contains sources",
|
|
8
|
-
"children": [
|
|
9
|
-
{
|
|
10
|
-
"name": "components",
|
|
11
|
-
"info": "reusable components"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"name": "utils",
|
|
15
|
-
"info": "utility functions"
|
|
16
|
-
}
|
|
17
|
-
]
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
"name": "docs",
|
|
21
|
-
"info": "documentation folder"
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}
|