@kntic/kntic 0.4.7 → 0.4.8
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/package.json +1 -1
- package/src/commands/update.js +20 -2
- package/src/commands/update.test.js +69 -0
- package/src/commands/usage.js +2 -2
package/package.json
CHANGED
package/src/commands/update.js
CHANGED
|
@@ -189,6 +189,8 @@ function extractLibOnly(tarball, destDir) {
|
|
|
189
189
|
* - .kntic/lib and .kntic/adrs are **replaced** (cleared first, then extracted).
|
|
190
190
|
* - .kntic/hooks/gia/internal is **updated** (existing files are overwritten or new files
|
|
191
191
|
* added, but files not present in the archive are preserved).
|
|
192
|
+
* - .kntic/hooks/gia/specific is **extracted only if the directory does not already exist**
|
|
193
|
+
* (one-time bootstrap; user customizations are never overwritten).
|
|
192
194
|
* - .kntic/gia/weights.json is **replaced** if present in the archive.
|
|
193
195
|
*
|
|
194
196
|
* @param {string} tarball – path to the .tar.gz file
|
|
@@ -198,6 +200,7 @@ function extractUpdate(tarball, destDir) {
|
|
|
198
200
|
const libDir = path.join(destDir, ".kntic", "lib");
|
|
199
201
|
const adrsDir = path.join(destDir, ".kntic", "adrs");
|
|
200
202
|
const giaInternalDir = path.join(destDir, ".kntic", "hooks", "gia", "internal");
|
|
203
|
+
const giaSpecificDir = path.join(destDir, ".kntic", "hooks", "gia", "specific");
|
|
201
204
|
const giaDir = path.join(destDir, ".kntic", "gia");
|
|
202
205
|
|
|
203
206
|
// Ensure target directories exist
|
|
@@ -211,6 +214,7 @@ function extractUpdate(tarball, destDir) {
|
|
|
211
214
|
clearDirectory(adrsDir);
|
|
212
215
|
|
|
213
216
|
// Note: gia/internal hooks are NOT cleared — update semantics (overwrite/add, preserve others)
|
|
217
|
+
// Note: gia/specific hooks are only extracted if the directory does NOT already exist
|
|
214
218
|
// Note: gia is NOT cleared — only weights.json is replaced
|
|
215
219
|
|
|
216
220
|
// Extract .kntic/lib/ and .kntic/adrs/ (guaranteed to be in the archive)
|
|
@@ -229,6 +233,20 @@ function extractUpdate(tarball, destDir) {
|
|
|
229
233
|
// No .kntic/hooks/gia/internal/ in the archive — that's fine
|
|
230
234
|
}
|
|
231
235
|
|
|
236
|
+
// Extract .kntic/hooks/gia/specific/ only if it does not already exist on disk.
|
|
237
|
+
// This is a one-time bootstrap — once the user has specific hooks, they are never
|
|
238
|
+
// overwritten by update.
|
|
239
|
+
if (!fs.existsSync(giaSpecificDir)) {
|
|
240
|
+
try {
|
|
241
|
+
execSync(
|
|
242
|
+
`tar xzf "${tarball}" -C "${destDir}" "./.kntic/hooks/gia/specific/"`,
|
|
243
|
+
{ stdio: "pipe" }
|
|
244
|
+
);
|
|
245
|
+
} catch (_) {
|
|
246
|
+
// No .kntic/hooks/gia/specific/ in the archive — that's fine
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
232
250
|
// Extract .kntic/gia/weights.json separately — archive may not contain it
|
|
233
251
|
try {
|
|
234
252
|
execSync(
|
|
@@ -256,7 +274,7 @@ async function update(options = {}) {
|
|
|
256
274
|
console.log("Updating .kntic/lib …");
|
|
257
275
|
extractLibOnly(tmpFile, ".");
|
|
258
276
|
} else {
|
|
259
|
-
console.log("Updating .kntic/lib, .kntic/adrs, .kntic/hooks/gia/internal, and .kntic/gia/weights.json …");
|
|
277
|
+
console.log("Updating .kntic/lib, .kntic/adrs, .kntic/hooks/gia/internal, .kntic/hooks/gia/specific (if new), and .kntic/gia/weights.json …");
|
|
260
278
|
extractUpdate(tmpFile, ".");
|
|
261
279
|
}
|
|
262
280
|
|
|
@@ -270,7 +288,7 @@ async function update(options = {}) {
|
|
|
270
288
|
if (libOnly) {
|
|
271
289
|
console.log("Done. .kntic/lib updated successfully.");
|
|
272
290
|
} else {
|
|
273
|
-
console.log("Done. .kntic/lib, .kntic/adrs, .kntic/hooks/gia/internal, and .kntic/gia/weights.json updated successfully.");
|
|
291
|
+
console.log("Done. .kntic/lib, .kntic/adrs, .kntic/hooks/gia/internal, .kntic/hooks/gia/specific (if new), and .kntic/gia/weights.json updated successfully.");
|
|
274
292
|
}
|
|
275
293
|
}
|
|
276
294
|
|
|
@@ -408,6 +408,75 @@ describe("extractUpdate", () => {
|
|
|
408
408
|
);
|
|
409
409
|
});
|
|
410
410
|
|
|
411
|
+
it("extracts .kntic/hooks/gia/specific when the directory does not exist", () => {
|
|
412
|
+
const tarball = createTarball(tmpDir, {
|
|
413
|
+
".kntic/lib/orchestrator.py": "# orchestrator\n",
|
|
414
|
+
".kntic/adrs/ADR-001.md": "# ADR 001\n",
|
|
415
|
+
".kntic/hooks/gia/specific/my-hook.sh": "#!/bin/sh\necho specific\n",
|
|
416
|
+
".kntic/hooks/gia/specific/another.sh": "#!/bin/sh\necho another\n",
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// specific dir does not exist yet
|
|
420
|
+
const specificDir = path.join(destDir, ".kntic", "hooks", "gia", "specific");
|
|
421
|
+
assert.ok(!fs.existsSync(specificDir), "specific dir must not exist before extraction");
|
|
422
|
+
|
|
423
|
+
extractUpdate(tarball, destDir);
|
|
424
|
+
|
|
425
|
+
// specific hooks must be extracted
|
|
426
|
+
assert.equal(
|
|
427
|
+
fs.readFileSync(path.join(specificDir, "my-hook.sh"), "utf8"),
|
|
428
|
+
"#!/bin/sh\necho specific\n"
|
|
429
|
+
);
|
|
430
|
+
assert.equal(
|
|
431
|
+
fs.readFileSync(path.join(specificDir, "another.sh"), "utf8"),
|
|
432
|
+
"#!/bin/sh\necho another\n"
|
|
433
|
+
);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it("does NOT overwrite .kntic/hooks/gia/specific when the directory already exists", () => {
|
|
437
|
+
const specificDir = path.join(destDir, ".kntic", "hooks", "gia", "specific");
|
|
438
|
+
fs.mkdirSync(specificDir, { recursive: true });
|
|
439
|
+
fs.writeFileSync(path.join(specificDir, "custom.sh"), "#!/bin/sh\necho custom\n");
|
|
440
|
+
|
|
441
|
+
const tarball = createTarball(tmpDir, {
|
|
442
|
+
".kntic/lib/orchestrator.py": "# orchestrator\n",
|
|
443
|
+
".kntic/adrs/ADR-001.md": "# ADR 001\n",
|
|
444
|
+
".kntic/hooks/gia/specific/my-hook.sh": "#!/bin/sh\necho from-archive\n",
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
extractUpdate(tarball, destDir);
|
|
448
|
+
|
|
449
|
+
// User's custom hook must be preserved
|
|
450
|
+
assert.equal(
|
|
451
|
+
fs.readFileSync(path.join(specificDir, "custom.sh"), "utf8"),
|
|
452
|
+
"#!/bin/sh\necho custom\n",
|
|
453
|
+
"user's custom specific hook must be preserved"
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
// Archive's specific hook must NOT be extracted
|
|
457
|
+
assert.ok(
|
|
458
|
+
!fs.existsSync(path.join(specificDir, "my-hook.sh")),
|
|
459
|
+
"archive specific hook must not be extracted when directory already exists"
|
|
460
|
+
);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it("works when archive has no .kntic/hooks/gia/specific and directory does not exist", () => {
|
|
464
|
+
const tarball = createTarball(tmpDir, {
|
|
465
|
+
".kntic/lib/orchestrator.py": "# orchestrator\n",
|
|
466
|
+
".kntic/adrs/ADR-001.md": "# ADR 001\n",
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
// Should not throw
|
|
470
|
+
extractUpdate(tarball, destDir);
|
|
471
|
+
|
|
472
|
+
// specific dir should not be created
|
|
473
|
+
const specificDir = path.join(destDir, ".kntic", "hooks", "gia", "specific");
|
|
474
|
+
assert.ok(
|
|
475
|
+
!fs.existsSync(specificDir),
|
|
476
|
+
"specific dir must not be created when not in archive"
|
|
477
|
+
);
|
|
478
|
+
});
|
|
479
|
+
|
|
411
480
|
it("preserves files outside .kntic/lib, .kntic/adrs, and .kntic/hooks/gia/internal", () => {
|
|
412
481
|
const knticDir = path.join(destDir, ".kntic");
|
|
413
482
|
fs.mkdirSync(knticDir, { recursive: true });
|
package/src/commands/usage.js
CHANGED
|
@@ -9,8 +9,8 @@ function usage() {
|
|
|
9
9
|
console.log(" start Build and start KNTIC services via docker compose (uses kntic.yml + .kntic.env)");
|
|
10
10
|
console.log(" --screen Run inside a GNU screen session");
|
|
11
11
|
console.log(" stop Stop KNTIC services via docker compose");
|
|
12
|
-
console.log(" update Download the latest KNTIC bootstrap and update .kntic/lib, .kntic/adrs, .kntic/hooks/gia/internal, and .kntic/gia/weights.json");
|
|
13
|
-
console.log(" --lib-only Update only .kntic/lib (skip
|
|
12
|
+
console.log(" update Download the latest KNTIC bootstrap and update .kntic/lib, .kntic/adrs, .kntic/hooks/gia/internal, .kntic/hooks/gia/specific (if new), and .kntic/gia/weights.json");
|
|
13
|
+
console.log(" --lib-only Update only .kntic/lib (skip adrs, hooks, and weights)");
|
|
14
14
|
console.log("");
|
|
15
15
|
}
|
|
16
16
|
|