@skillsmith/core 0.12.2 → 0.12.4
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/CHANGELOG.md +173 -0
- package/README.md +2 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/config/owned-lock.acquire.d.ts +8 -0
- package/dist/src/config/owned-lock.acquire.d.ts.map +1 -1
- package/dist/src/config/owned-lock.acquire.js +19 -4
- package/dist/src/config/owned-lock.acquire.js.map +1 -1
- package/dist/src/config/owned-lock.claim.d.ts +4 -2
- package/dist/src/config/owned-lock.claim.d.ts.map +1 -1
- package/dist/src/config/owned-lock.claim.js +42 -8
- package/dist/src/config/owned-lock.claim.js.map +1 -1
- package/dist/src/config/owned-lock.d.ts.map +1 -1
- package/dist/src/config/owned-lock.js +1 -0
- package/dist/src/config/owned-lock.js.map +1 -1
- package/dist/src/config/owned-lock.test.js +126 -2
- package/dist/src/config/owned-lock.test.js.map +1 -1
- package/dist/src/config/owned-lock.types.d.ts +9 -0
- package/dist/src/config/owned-lock.types.d.ts.map +1 -1
- package/dist/src/db/createDatabase.d.ts.map +1 -1
- package/dist/src/db/createDatabase.js +0 -2
- package/dist/src/db/createDatabase.js.map +1 -1
- package/dist/src/exports/services.install.d.ts +1 -0
- package/dist/src/exports/services.install.d.ts.map +1 -1
- package/dist/src/exports/services.install.js +5 -0
- package/dist/src/exports/services.install.js.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/install/fan-out.cleanup.d.ts +37 -0
- package/dist/src/install/fan-out.cleanup.d.ts.map +1 -0
- package/dist/src/install/fan-out.cleanup.js +75 -0
- package/dist/src/install/fan-out.cleanup.js.map +1 -0
- package/dist/src/install/fan-out.d.ts +41 -31
- package/dist/src/install/fan-out.d.ts.map +1 -1
- package/dist/src/install/fan-out.js +213 -112
- package/dist/src/install/fan-out.js.map +1 -1
- package/dist/src/install/fan-out.leftovers.d.ts +60 -0
- package/dist/src/install/fan-out.leftovers.d.ts.map +1 -0
- package/dist/src/install/fan-out.leftovers.js +251 -0
- package/dist/src/install/fan-out.leftovers.js.map +1 -0
- package/dist/src/install/fan-out.locks.d.ts +12 -0
- package/dist/src/install/fan-out.locks.d.ts.map +1 -0
- package/dist/src/install/fan-out.locks.js +114 -0
- package/dist/src/install/fan-out.locks.js.map +1 -0
- package/dist/src/install/fan-out.manifest.d.ts +64 -0
- package/dist/src/install/fan-out.manifest.d.ts.map +1 -0
- package/dist/src/install/fan-out.manifest.js +130 -0
- package/dist/src/install/fan-out.manifest.js.map +1 -0
- package/dist/src/install/fan-out.overwrite.d.ts +51 -0
- package/dist/src/install/fan-out.overwrite.d.ts.map +1 -0
- package/dist/src/install/fan-out.overwrite.js +343 -0
- package/dist/src/install/fan-out.overwrite.js.map +1 -0
- package/dist/src/install/remove-if-same.d.ts +58 -0
- package/dist/src/install/remove-if-same.d.ts.map +1 -0
- package/dist/src/install/remove-if-same.js +222 -0
- package/dist/src/install/remove-if-same.js.map +1 -0
- package/dist/src/provenance/backfill.d.ts.map +1 -1
- package/dist/src/provenance/backfill.js +15 -2
- package/dist/src/provenance/backfill.js.map +1 -1
- package/dist/src/scripts/__tests__/scan-imported-skills.test.js +9 -1
- package/dist/src/scripts/__tests__/scan-imported-skills.test.js.map +1 -1
- package/dist/src/scripts/scan-imported-skills.d.ts +7 -1
- package/dist/src/scripts/scan-imported-skills.d.ts.map +1 -1
- package/dist/src/scripts/scan-imported-skills.js +15 -2
- package/dist/src/scripts/scan-imported-skills.js.map +1 -1
- package/dist/src/scripts/skill-scanner/allowlist.d.ts +10 -0
- package/dist/src/scripts/skill-scanner/allowlist.d.ts.map +1 -1
- package/dist/src/scripts/skill-scanner/allowlist.js +10 -0
- package/dist/src/scripts/skill-scanner/allowlist.js.map +1 -1
- package/dist/src/scripts/skill-scanner/index.d.ts +8 -0
- package/dist/src/scripts/skill-scanner/index.d.ts.map +1 -1
- package/dist/src/scripts/skill-scanner/index.js +13 -5
- package/dist/src/scripts/skill-scanner/index.js.map +1 -1
- package/dist/src/scripts/skill-scanner/trust-scorer.d.ts.map +1 -1
- package/dist/src/scripts/skill-scanner/trust-scorer.js +6 -0
- package/dist/src/scripts/skill-scanner/trust-scorer.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.action-context.d.ts +15 -0
- package/dist/src/security/scanner/SecurityScanner.action-context.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.action-context.js +209 -0
- package/dist/src/security/scanner/SecurityScanner.action-context.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.d.ts +25 -0
- package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.helpers.d.ts +40 -1
- package/dist/src/security/scanner/SecurityScanner.helpers.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.helpers.js +88 -51
- package/dist/src/security/scanner/SecurityScanner.helpers.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.js +39 -6
- package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.pii.d.ts +30 -0
- package/dist/src/security/scanner/SecurityScanner.pii.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.pii.js +8 -1
- package/dist/src/security/scanner/SecurityScanner.pii.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.prose-lexicon.d.ts +60 -0
- package/dist/src/security/scanner/SecurityScanner.prose-lexicon.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.prose-lexicon.js +228 -0
- package/dist/src/security/scanner/SecurityScanner.prose-lexicon.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.scanners.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.scanners.js +42 -5
- package/dist/src/security/scanner/SecurityScanner.scanners.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.value-gate.d.ts +69 -0
- package/dist/src/security/scanner/SecurityScanner.value-gate.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.value-gate.js +271 -0
- package/dist/src/security/scanner/SecurityScanner.value-gate.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.weak-passwords.d.ts +55 -0
- package/dist/src/security/scanner/SecurityScanner.weak-passwords.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.weak-passwords.js +308 -0
- package/dist/src/security/scanner/SecurityScanner.weak-passwords.js.map +1 -0
- package/dist/src/security/scanner/patterns.d.ts +61 -6
- package/dist/src/security/scanner/patterns.d.ts.map +1 -1
- package/dist/src/security/scanner/patterns.js +70 -61
- package/dist/src/security/scanner/patterns.js.map +1 -1
- package/dist/src/security/scanner/patterns.sensitive-path.d.ts +73 -0
- package/dist/src/security/scanner/patterns.sensitive-path.d.ts.map +1 -0
- package/dist/src/security/scanner/patterns.sensitive-path.js +192 -0
- package/dist/src/security/scanner/patterns.sensitive-path.js.map +1 -0
- package/dist/src/security/scanner/regex-utils.d.ts +31 -17
- package/dist/src/security/scanner/regex-utils.d.ts.map +1 -1
- package/dist/src/security/scanner/regex-utils.js +31 -17
- package/dist/src/security/scanner/regex-utils.js.map +1 -1
- package/dist/src/security/scanner/types.d.ts +9 -0
- package/dist/src/security/scanner/types.d.ts.map +1 -1
- package/dist/src/services/agent-pack/prompt-source.d.ts.map +1 -1
- package/dist/src/services/agent-pack/prompt-source.js +3 -2
- package/dist/src/services/agent-pack/prompt-source.js.map +1 -1
- package/dist/src/services/skill-installation.content.d.ts +7 -2
- package/dist/src/services/skill-installation.content.d.ts.map +1 -1
- package/dist/src/services/skill-installation.content.js +75 -28
- package/dist/src/services/skill-installation.content.js.map +1 -1
- package/dist/src/services/skill-installation.helpers.d.ts.map +1 -1
- package/dist/src/services/skill-installation.helpers.js +8 -0
- package/dist/src/services/skill-installation.helpers.js.map +1 -1
- package/dist/src/services/skill-installation.io.d.ts +1 -29
- package/dist/src/services/skill-installation.io.d.ts.map +1 -1
- package/dist/src/services/skill-installation.io.dirs.d.ts +15 -0
- package/dist/src/services/skill-installation.io.dirs.d.ts.map +1 -0
- package/dist/src/services/skill-installation.io.dirs.js +84 -0
- package/dist/src/services/skill-installation.io.dirs.js.map +1 -0
- package/dist/src/services/skill-installation.io.js +6 -176
- package/dist/src/services/skill-installation.io.js.map +1 -1
- package/dist/src/services/skill-installation.io.rollback.d.ts +138 -0
- package/dist/src/services/skill-installation.io.rollback.d.ts.map +1 -0
- package/dist/src/services/skill-installation.io.rollback.js +218 -0
- package/dist/src/services/skill-installation.io.rollback.js.map +1 -0
- package/dist/src/services/skill-installation.io.write.d.ts +69 -0
- package/dist/src/services/skill-installation.io.write.d.ts.map +1 -0
- package/dist/src/services/skill-installation.io.write.js +417 -0
- package/dist/src/services/skill-installation.io.write.js.map +1 -0
- package/dist/src/services/skill-installation.service.d.ts.map +1 -1
- package/dist/src/services/skill-installation.service.finalize.d.ts +62 -0
- package/dist/src/services/skill-installation.service.finalize.d.ts.map +1 -0
- package/dist/src/services/skill-installation.service.finalize.js +136 -0
- package/dist/src/services/skill-installation.service.finalize.js.map +1 -0
- package/dist/src/services/skill-installation.service.js +66 -80
- package/dist/src/services/skill-installation.service.js.map +1 -1
- package/dist/src/services/skill-installation.target-guard.d.ts +82 -0
- package/dist/src/services/skill-installation.target-guard.d.ts.map +1 -0
- package/dist/src/services/skill-installation.target-guard.js +410 -0
- package/dist/src/services/skill-installation.target-guard.js.map +1 -0
- package/dist/src/services/skill-installation.types.d.ts +13 -1
- package/dist/src/services/skill-installation.types.d.ts.map +1 -1
- package/dist/src/services/skill-installation.types.js.map +1 -1
- package/dist/src/services/skill-installation.uninstall.d.ts +3 -1
- package/dist/src/services/skill-installation.uninstall.d.ts.map +1 -1
- package/dist/src/services/skill-installation.uninstall.helpers.d.ts +59 -0
- package/dist/src/services/skill-installation.uninstall.helpers.d.ts.map +1 -0
- package/dist/src/services/skill-installation.uninstall.helpers.js +124 -0
- package/dist/src/services/skill-installation.uninstall.helpers.js.map +1 -0
- package/dist/src/services/skill-installation.uninstall.js +148 -25
- package/dist/src/services/skill-installation.uninstall.js.map +1 -1
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +2 -0
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/safe-fs.d.ts +69 -0
- package/dist/src/utils/safe-fs.d.ts.map +1 -1
- package/dist/src/utils/safe-fs.js +113 -2
- package/dist/src/utils/safe-fs.js.map +1 -1
- package/dist/src/utils/skill-name.d.ts +19 -0
- package/dist/src/utils/skill-name.d.ts.map +1 -0
- package/dist/src/utils/skill-name.js +26 -0
- package/dist/src/utils/skill-name.js.map +1 -0
- package/dist/src/utils/skill-name.test.d.ts +2 -0
- package/dist/src/utils/skill-name.test.d.ts.map +1 -0
- package/dist/src/utils/skill-name.test.js +34 -0
- package/dist/src/utils/skill-name.test.js.map +1 -0
- package/dist/tests/install/fan-out.test.js +1951 -13
- package/dist/tests/install/fan-out.test.js.map +1 -1
- package/dist/tests/install/remove-if-same.test.d.ts +2 -0
- package/dist/tests/install/remove-if-same.test.d.ts.map +1 -0
- package/dist/tests/install/remove-if-same.test.js +298 -0
- package/dist/tests/install/remove-if-same.test.js.map +1 -0
- package/dist/tests/integration/fan-out-lock-contention.test.d.ts +11 -0
- package/dist/tests/integration/fan-out-lock-contention.test.d.ts.map +1 -0
- package/dist/tests/integration/fan-out-lock-contention.test.js +53 -0
- package/dist/tests/integration/fan-out-lock-contention.test.js.map +1 -0
- package/dist/tests/provenance/backfill.test.js +43 -0
- package/dist/tests/provenance/backfill.test.js.map +1 -1
- package/dist/tests/security/ContinuousSecurity.performance.test.js +12 -7
- package/dist/tests/security/ContinuousSecurity.performance.test.js.map +1 -1
- package/dist/tests/security/ContinuousSecurity.test.js +14 -2
- package/dist/tests/security/ContinuousSecurity.test.js.map +1 -1
- package/dist/tests/security/ai-defence-multiline-promotion.test.d.ts +10 -12
- package/dist/tests/security/ai-defence-multiline-promotion.test.d.ts.map +1 -1
- package/dist/tests/security/ai-defence-multiline-promotion.test.js +26 -33
- package/dist/tests/security/ai-defence-multiline-promotion.test.js.map +1 -1
- package/dist/tests/security/nested-instruction-long-attribute.test.js +20 -10
- package/dist/tests/security/nested-instruction-long-attribute.test.js.map +1 -1
- package/dist/tests/security/scanner-evidence-tiers.test.js +15 -0
- package/dist/tests/security/scanner-evidence-tiers.test.js.map +1 -1
- package/dist/tests/security/scanner-multiline-cap.test.d.ts +21 -0
- package/dist/tests/security/scanner-multiline-cap.test.d.ts.map +1 -0
- package/dist/tests/security/scanner-multiline-cap.test.js +152 -0
- package/dist/tests/security/scanner-multiline-cap.test.js.map +1 -0
- package/dist/tests/security/scanner-regression-guard.test.js +66 -1
- package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
- package/dist/tests/security/scanner-witness-sw1.test.d.ts +32 -0
- package/dist/tests/security/scanner-witness-sw1.test.d.ts.map +1 -0
- package/dist/tests/security/scanner-witness-sw1.test.js +255 -0
- package/dist/tests/security/scanner-witness-sw1.test.js.map +1 -0
- package/dist/tests/security/sensitive-path-adversarial-review.test.d.ts +2 -0
- package/dist/tests/security/sensitive-path-adversarial-review.test.d.ts.map +1 -0
- package/dist/tests/security/sensitive-path-adversarial-review.test.js +313 -0
- package/dist/tests/security/sensitive-path-adversarial-review.test.js.map +1 -0
- package/dist/tests/security/sensitive-path-boolean-flag.test.d.ts +2 -0
- package/dist/tests/security/sensitive-path-boolean-flag.test.d.ts.map +1 -0
- package/dist/tests/security/sensitive-path-boolean-flag.test.js +151 -0
- package/dist/tests/security/sensitive-path-boolean-flag.test.js.map +1 -0
- package/dist/tests/security/sensitive-path-fp.test.js +314 -0
- package/dist/tests/security/sensitive-path-fp.test.js.map +1 -1
- package/dist/tests/security/sensitive-path-prefixed-secrets.test.d.ts +2 -0
- package/dist/tests/security/sensitive-path-prefixed-secrets.test.d.ts.map +1 -0
- package/dist/tests/security/sensitive-path-prefixed-secrets.test.js +176 -0
- package/dist/tests/security/sensitive-path-prefixed-secrets.test.js.map +1 -0
- package/dist/tests/security/smi5879-corroboration.core.test.js +44 -0
- package/dist/tests/security/smi5879-corroboration.core.test.js.map +1 -1
- package/dist/tests/security/weak-password-lexicon.test.d.ts +18 -0
- package/dist/tests/security/weak-password-lexicon.test.d.ts.map +1 -0
- package/dist/tests/security/weak-password-lexicon.test.js +132 -0
- package/dist/tests/security/weak-password-lexicon.test.js.map +1 -0
- package/dist/tests/skill-scanner/allowlist.test.js +58 -4
- package/dist/tests/skill-scanner/allowlist.test.js.map +1 -1
- package/dist/tests/skill-scanner/categorizer.test.d.ts +2 -0
- package/dist/tests/skill-scanner/categorizer.test.d.ts.map +1 -0
- package/dist/tests/skill-scanner/categorizer.test.js +71 -0
- package/dist/tests/skill-scanner/categorizer.test.js.map +1 -0
- package/dist/tests/skill-scanner/cli-guard.test.d.ts +23 -0
- package/dist/tests/skill-scanner/cli-guard.test.d.ts.map +1 -0
- package/dist/tests/skill-scanner/cli-guard.test.js +71 -0
- package/dist/tests/skill-scanner/cli-guard.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.content.test.js +59 -0
- package/dist/tests/unit/services/skill-installation.content.test.js.map +1 -1
- package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.js +35 -14
- package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.js.map +1 -1
- package/dist/tests/unit/services/skill-installation.io.rollback.test.d.ts +2 -0
- package/dist/tests/unit/services/skill-installation.io.rollback.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.io.rollback.test.js +984 -0
- package/dist/tests/unit/services/skill-installation.io.rollback.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.io.rollback.unit.test.d.ts +2 -0
- package/dist/tests/unit/services/skill-installation.io.rollback.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.io.rollback.unit.test.js +148 -0
- package/dist/tests/unit/services/skill-installation.io.rollback.unit.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.error-codes.test.js +19 -0
- package/dist/tests/unit/services/skill-installation.service.error-codes.test.js.map +1 -1
- package/dist/tests/unit/services/skill-installation.service.finalize.test.d.ts +2 -0
- package/dist/tests/unit/services/skill-installation.service.finalize.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.finalize.test.js +147 -0
- package/dist/tests/unit/services/skill-installation.service.finalize.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.sensitive-path-fp.test.d.ts +29 -0
- package/dist/tests/unit/services/skill-installation.service.sensitive-path-fp.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.sensitive-path-fp.test.js +200 -0
- package/dist/tests/unit/services/skill-installation.service.sensitive-path-fp.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.test.js +43 -0
- package/dist/tests/unit/services/skill-installation.service.test.js.map +1 -1
- package/dist/tests/unit/services/skill-installation.target-guard.test.d.ts +2 -0
- package/dist/tests/unit/services/skill-installation.target-guard.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.target-guard.test.js +590 -0
- package/dist/tests/unit/services/skill-installation.target-guard.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.uninstall.guard.test.d.ts +2 -0
- package/dist/tests/unit/services/skill-installation.uninstall.guard.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.uninstall.guard.test.js +473 -0
- package/dist/tests/unit/services/skill-installation.uninstall.guard.test.js.map +1 -0
- package/dist/tests/utils/safe-fs.test.js +129 -2
- package/dist/tests/utils/safe-fs.test.js.map +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-6529 round 15 (cross-model review, Critical): uninstall never deletes a
|
|
3
|
+
* skill folder that is a git working tree, and removes only the folder it
|
|
4
|
+
* checked. Before this, `remove` on a git clone adopted it and ran
|
|
5
|
+
* `rm -rf` on it, `.git` and unpushed work included.
|
|
6
|
+
*/
|
|
7
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
8
|
+
import * as fs from 'fs/promises';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import * as os from 'os';
|
|
11
|
+
import { SkillInstallationService } from '../../../src/services/skill-installation.service.js';
|
|
12
|
+
import { SkillRepository } from '../../../src/repositories/SkillRepository.js';
|
|
13
|
+
import { SkillDependencyRepository } from '../../../src/repositories/SkillDependencyRepository.js';
|
|
14
|
+
import { createTestDatabase } from '../../helpers/database.js';
|
|
15
|
+
// One-shot: the next rename of this exact path first has another program move
|
|
16
|
+
// the folder aside and put its own folder there.
|
|
17
|
+
const swapBeforeRename = vi.hoisted(() => ({ path: null }));
|
|
18
|
+
// One-shot: while this path is being parked, another install claims the same
|
|
19
|
+
// manifest key by rewriting that record's installPath.
|
|
20
|
+
const claimOnRename = vi.hoisted(() => ({
|
|
21
|
+
path: null,
|
|
22
|
+
manifestPath: null,
|
|
23
|
+
key: null,
|
|
24
|
+
newInstallPath: null,
|
|
25
|
+
reinstalledAt: null,
|
|
26
|
+
newVersion: null,
|
|
27
|
+
}));
|
|
28
|
+
// Every rename onto this path fails, so the manifest write fails after the
|
|
29
|
+
// skill folder is already gone.
|
|
30
|
+
const failRenameTo = vi.hoisted(() => ({ path: null }));
|
|
31
|
+
// Round 25: `access` of this exact path fails, so the existence check cannot
|
|
32
|
+
// tell whether the skill is on disk. Round 26: `throws` chooses WHAT it fails
|
|
33
|
+
// with — the default is a coded EACCES, and a test can supply an error with no
|
|
34
|
+
// `code`, or a value that is not an Error at all.
|
|
35
|
+
const accessFailFor = vi.hoisted(() => ({
|
|
36
|
+
path: null,
|
|
37
|
+
throws: null,
|
|
38
|
+
}));
|
|
39
|
+
// Round 25: `readdir` of this exact folder fails, so the parked-leftover scan
|
|
40
|
+
// cannot look.
|
|
41
|
+
const readdirFailFor = vi.hoisted(() => ({ path: null }));
|
|
42
|
+
// `removeIfSame` imports `node:fs/promises`; `ManifestManager` imports
|
|
43
|
+
// `fs/promises`. Both get the same hooks.
|
|
44
|
+
const makeFsMock = vi.hoisted(() => (actual) => {
|
|
45
|
+
const rename = async (from, to) => {
|
|
46
|
+
if (String(from) === swapBeforeRename.path) {
|
|
47
|
+
swapBeforeRename.path = null;
|
|
48
|
+
await actual.rename(from, `${String(from)}-moved`);
|
|
49
|
+
await actual.mkdir(from);
|
|
50
|
+
await actual.writeFile(`${String(from)}/KEEP.md`, 'not ours', 'utf-8');
|
|
51
|
+
}
|
|
52
|
+
if (String(from) === claimOnRename.path && claimOnRename.manifestPath !== null) {
|
|
53
|
+
const manifestFile = claimOnRename.manifestPath;
|
|
54
|
+
const key = claimOnRename.key ?? '';
|
|
55
|
+
const claimed = claimOnRename.newInstallPath ?? '';
|
|
56
|
+
claimOnRename.path = null;
|
|
57
|
+
const reinstalledAt = claimOnRename.reinstalledAt;
|
|
58
|
+
const newVersion = claimOnRename.newVersion;
|
|
59
|
+
const raw = JSON.parse(await actual.readFile(manifestFile, 'utf-8'));
|
|
60
|
+
const entry = raw.installedSkills[key];
|
|
61
|
+
if (entry) {
|
|
62
|
+
if (claimed !== '')
|
|
63
|
+
entry.installPath = claimed;
|
|
64
|
+
if (reinstalledAt !== null) {
|
|
65
|
+
entry.installedAt = reinstalledAt;
|
|
66
|
+
entry.lastUpdated = reinstalledAt;
|
|
67
|
+
}
|
|
68
|
+
if (newVersion !== null)
|
|
69
|
+
entry.version = newVersion;
|
|
70
|
+
}
|
|
71
|
+
await actual.writeFile(manifestFile, JSON.stringify(raw, null, 2));
|
|
72
|
+
}
|
|
73
|
+
if (String(to) === failRenameTo.path) {
|
|
74
|
+
throw Object.assign(new Error(`EACCES: permission denied, rename '${String(to)}'`), {
|
|
75
|
+
code: 'EACCES',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return actual.rename(from, to);
|
|
79
|
+
};
|
|
80
|
+
const access = async (p, mode) => {
|
|
81
|
+
if (String(p) === accessFailFor.path) {
|
|
82
|
+
if (accessFailFor.throws !== null)
|
|
83
|
+
throw accessFailFor.throws.value;
|
|
84
|
+
throw Object.assign(new Error(`EACCES: permission denied, access '${String(p)}'`), {
|
|
85
|
+
code: 'EACCES',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return actual.access(p, mode);
|
|
89
|
+
};
|
|
90
|
+
const readdir = (async (...args) => {
|
|
91
|
+
if (String(args[0]) === readdirFailFor.path) {
|
|
92
|
+
throw Object.assign(new Error(`EACCES: permission denied, scandir '${String(args[0])}'`), {
|
|
93
|
+
code: 'EACCES',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return actual.readdir(...args);
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
...actual,
|
|
100
|
+
default: { ...actual, rename, access, readdir },
|
|
101
|
+
rename,
|
|
102
|
+
access,
|
|
103
|
+
readdir,
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
vi.mock('node:fs/promises', async (importOriginal) => makeFsMock(await importOriginal()));
|
|
107
|
+
vi.mock('fs/promises', async (importOriginal) => makeFsMock(await importOriginal()));
|
|
108
|
+
let tmpDir;
|
|
109
|
+
let skillsDir;
|
|
110
|
+
let manifestPath;
|
|
111
|
+
let db;
|
|
112
|
+
function createService(onProgress) {
|
|
113
|
+
return new SkillInstallationService({
|
|
114
|
+
db,
|
|
115
|
+
skillRepo: new SkillRepository(db),
|
|
116
|
+
skillDependencyRepo: new SkillDependencyRepository(db),
|
|
117
|
+
skillsDir,
|
|
118
|
+
manifestPath,
|
|
119
|
+
...(onProgress !== undefined && { onProgress }),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/** Record `name` in the manifest as installed at `installPath`. */
|
|
123
|
+
async function track(name, installPath) {
|
|
124
|
+
// installedAt is ahead of every file, so the non-force check sees no edits.
|
|
125
|
+
const later = new Date(Date.now() + 60_000).toISOString();
|
|
126
|
+
const manifest = {
|
|
127
|
+
version: '1.0.0',
|
|
128
|
+
installedSkills: {
|
|
129
|
+
[name]: {
|
|
130
|
+
id: `author/${name}`,
|
|
131
|
+
name,
|
|
132
|
+
version: '1.0.0',
|
|
133
|
+
source: `github:author/${name}`,
|
|
134
|
+
installPath,
|
|
135
|
+
installedAt: later,
|
|
136
|
+
lastUpdated: later,
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
141
|
+
}
|
|
142
|
+
/** Record `name` with no install timestamps, as an older writer did. */
|
|
143
|
+
async function trackLegacy(name, installPath) {
|
|
144
|
+
const manifest = {
|
|
145
|
+
version: '1.0.0',
|
|
146
|
+
installedSkills: {
|
|
147
|
+
[name]: {
|
|
148
|
+
id: `author/${name}`,
|
|
149
|
+
name,
|
|
150
|
+
version: '1.0.0',
|
|
151
|
+
source: `github:author/${name}`,
|
|
152
|
+
installPath,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
157
|
+
}
|
|
158
|
+
/** Record `name` with an extra field of the given value, as another tool might. */
|
|
159
|
+
async function trackWithExtra(name, installPath, extra) {
|
|
160
|
+
const later = new Date(Date.now() + 60_000).toISOString();
|
|
161
|
+
const manifest = {
|
|
162
|
+
version: '1.0.0',
|
|
163
|
+
installedSkills: {
|
|
164
|
+
[name]: {
|
|
165
|
+
id: `author/${name}`,
|
|
166
|
+
name,
|
|
167
|
+
version: '1.0.0',
|
|
168
|
+
source: `github:author/${name}`,
|
|
169
|
+
installPath,
|
|
170
|
+
installedAt: later,
|
|
171
|
+
lastUpdated: later,
|
|
172
|
+
tags: extra,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
177
|
+
}
|
|
178
|
+
async function manifestEntry(name) {
|
|
179
|
+
const raw = await fs.readFile(manifestPath, 'utf-8').catch(() => null);
|
|
180
|
+
if (raw === null)
|
|
181
|
+
return undefined;
|
|
182
|
+
return JSON.parse(raw).installedSkills[name];
|
|
183
|
+
}
|
|
184
|
+
async function makeClone(dir) {
|
|
185
|
+
await fs.mkdir(path.join(dir, '.git'), { recursive: true });
|
|
186
|
+
await fs.writeFile(path.join(dir, '.git', 'HEAD'), 'ref: refs/heads/main\n');
|
|
187
|
+
await fs.writeFile(path.join(dir, 'SKILL.md'), '# Local work\n');
|
|
188
|
+
}
|
|
189
|
+
beforeEach(async () => {
|
|
190
|
+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'uninstall-guard-'));
|
|
191
|
+
skillsDir = path.join(tmpDir, 'skills');
|
|
192
|
+
manifestPath = path.join(tmpDir, 'manifest.json');
|
|
193
|
+
await fs.mkdir(skillsDir, { recursive: true });
|
|
194
|
+
db = await createTestDatabase();
|
|
195
|
+
});
|
|
196
|
+
afterEach(async () => {
|
|
197
|
+
swapBeforeRename.path = null;
|
|
198
|
+
claimOnRename.path = null;
|
|
199
|
+
claimOnRename.manifestPath = null;
|
|
200
|
+
claimOnRename.reinstalledAt = null;
|
|
201
|
+
claimOnRename.newVersion = null;
|
|
202
|
+
claimOnRename.newInstallPath = null;
|
|
203
|
+
failRenameTo.path = null;
|
|
204
|
+
accessFailFor.path = null;
|
|
205
|
+
accessFailFor.throws = null;
|
|
206
|
+
readdirFailFor.path = null;
|
|
207
|
+
db.close();
|
|
208
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
209
|
+
});
|
|
210
|
+
describe('uninstall never deletes a git working tree (SMI-6529 round 15)', () => {
|
|
211
|
+
it('refuses an untracked skill folder that is a git clone, and adopts nothing', async () => {
|
|
212
|
+
const clone = path.join(skillsDir, 'clone-skill');
|
|
213
|
+
await makeClone(clone);
|
|
214
|
+
const result = await createService().uninstall('clone-skill');
|
|
215
|
+
expect(result.success).toBe(false);
|
|
216
|
+
expect(result.message).toContain('is a git working tree');
|
|
217
|
+
expect(await fs.readFile(path.join(clone, '.git', 'HEAD'), 'utf-8')).toContain('main');
|
|
218
|
+
expect(await manifestEntry('clone-skill')).toBeUndefined();
|
|
219
|
+
});
|
|
220
|
+
it('refuses a tracked skill folder that has become a git clone, even with force', async () => {
|
|
221
|
+
const clone = path.join(skillsDir, 'tracked-clone');
|
|
222
|
+
await makeClone(clone);
|
|
223
|
+
await track('tracked-clone', clone);
|
|
224
|
+
const result = await createService().uninstall('tracked-clone', { force: true });
|
|
225
|
+
expect(result.success).toBe(false);
|
|
226
|
+
expect(result.message).toContain('even with force');
|
|
227
|
+
expect(await fs.readFile(path.join(clone, 'SKILL.md'), 'utf-8')).toBe('# Local work\n');
|
|
228
|
+
expect(await manifestEntry('tracked-clone')).toBeDefined();
|
|
229
|
+
});
|
|
230
|
+
it('removes a symlinked skill and leaves the clone it points at alone', async () => {
|
|
231
|
+
const clone = path.join(tmpDir, 'dev', 'linked-skill');
|
|
232
|
+
await makeClone(clone);
|
|
233
|
+
const link = path.join(skillsDir, 'linked-skill');
|
|
234
|
+
await fs.symlink(clone, link);
|
|
235
|
+
await track('linked-skill', link);
|
|
236
|
+
const result = await createService().uninstall('linked-skill', { force: true });
|
|
237
|
+
expect(result.success).toBe(true);
|
|
238
|
+
await expect(fs.lstat(link)).rejects.toMatchObject({ code: 'ENOENT' });
|
|
239
|
+
expect(await fs.readFile(path.join(clone, 'SKILL.md'), 'utf-8')).toBe('# Local work\n');
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
// SMI-6529 round 28 (pre-merge gate, PR-07): a progress listener that throws
|
|
243
|
+
// must not change the uninstall's outcome — that part was deliberate — but it
|
|
244
|
+
// must not vanish either.
|
|
245
|
+
describe('uninstall reports a progress listener that threw (SMI-6529 round 28)', () => {
|
|
246
|
+
// Round 29 (gate confirmation): the success path was covered; the exits that
|
|
247
|
+
// carry no warning of their own were not, and those are exactly where a
|
|
248
|
+
// listener failure used to disappear.
|
|
249
|
+
it('still says the listener threw when the uninstall exits early', async () => {
|
|
250
|
+
const result = await createService(() => {
|
|
251
|
+
throw new Error('listener blew up');
|
|
252
|
+
}).uninstall('never-installed-skill');
|
|
253
|
+
expect(result.success).toBe(false);
|
|
254
|
+
expect(result.message).toContain('is not installed');
|
|
255
|
+
expect(result.warning).toContain('progress listener threw');
|
|
256
|
+
});
|
|
257
|
+
it('finishes the uninstall and says the listener threw', async () => {
|
|
258
|
+
const installPath = path.join(skillsDir, 'listener-skill');
|
|
259
|
+
await fs.mkdir(installPath);
|
|
260
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
261
|
+
await track('listener-skill', installPath);
|
|
262
|
+
const result = await createService(() => {
|
|
263
|
+
throw new Error('listener blew up');
|
|
264
|
+
}).uninstall('listener-skill', { force: true });
|
|
265
|
+
// The outcome is unchanged: the skill really is gone.
|
|
266
|
+
expect(result.success).toBe(true);
|
|
267
|
+
await expect(fs.lstat(installPath)).rejects.toMatchObject({ code: 'ENOENT' });
|
|
268
|
+
// And the failure is not silent.
|
|
269
|
+
expect(result.warning).toContain('progress listener threw');
|
|
270
|
+
expect(result.warning).toContain('listener blew up');
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
// SMI-6529 round 25 (cross-model review): a check that could not run is not a
|
|
274
|
+
// check that found nothing. Both of these used to be silent.
|
|
275
|
+
describe('uninstall says when it could not tell (SMI-6529 round 25)', () => {
|
|
276
|
+
it('does not say "not installed" when the check itself failed', async () => {
|
|
277
|
+
const installPath = path.join(skillsDir, 'unreadable-skill');
|
|
278
|
+
await fs.mkdir(installPath);
|
|
279
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
280
|
+
accessFailFor.path = installPath;
|
|
281
|
+
const result = await createService().uninstall('unreadable-skill');
|
|
282
|
+
expect(result.success).toBe(false);
|
|
283
|
+
expect(result.message).toContain('Could not tell whether');
|
|
284
|
+
expect(result.message).toContain('EACCES');
|
|
285
|
+
// The skill is still there: the user is not sent away from it.
|
|
286
|
+
expect(await fs.readFile(path.join(installPath, 'SKILL.md'), 'utf-8')).toBe('# Installed\n');
|
|
287
|
+
});
|
|
288
|
+
// Round 26 (cross-model review): the round-25 guard read
|
|
289
|
+
// `code !== undefined && code !== 'ENOENT'`, so an error carrying no code at
|
|
290
|
+
// all fell through to "not installed" — the same false absence it fixed.
|
|
291
|
+
it('does not say "not installed" when the check failed with no error code', async () => {
|
|
292
|
+
const installPath = path.join(skillsDir, 'uncoded-skill');
|
|
293
|
+
await fs.mkdir(installPath);
|
|
294
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
295
|
+
accessFailFor.path = installPath;
|
|
296
|
+
accessFailFor.throws = { value: new Error('filesystem went away') };
|
|
297
|
+
const result = await createService().uninstall('uncoded-skill');
|
|
298
|
+
expect(result.success).toBe(false);
|
|
299
|
+
expect(result.message).toContain('Could not tell whether');
|
|
300
|
+
expect(result.message).toContain('filesystem went away');
|
|
301
|
+
expect(await fs.readFile(path.join(installPath, 'SKILL.md'), 'utf-8')).toBe('# Installed\n');
|
|
302
|
+
});
|
|
303
|
+
it('survives a thrown value that is not an Error at all', async () => {
|
|
304
|
+
const installPath = path.join(skillsDir, 'nonerror-skill');
|
|
305
|
+
await fs.mkdir(installPath);
|
|
306
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
307
|
+
accessFailFor.path = installPath;
|
|
308
|
+
accessFailFor.throws = { value: null };
|
|
309
|
+
const result = await createService().uninstall('nonerror-skill');
|
|
310
|
+
expect(result.success).toBe(false);
|
|
311
|
+
expect(result.message).toContain('Could not tell whether');
|
|
312
|
+
expect(await fs.readFile(path.join(installPath, 'SKILL.md'), 'utf-8')).toBe('# Installed\n');
|
|
313
|
+
});
|
|
314
|
+
it('says when it could not look for parked leftovers', async () => {
|
|
315
|
+
const installPath = path.join(skillsDir, 'parkscan-skill');
|
|
316
|
+
await fs.mkdir(installPath);
|
|
317
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
318
|
+
await track('parkscan-skill', installPath);
|
|
319
|
+
readdirFailFor.path = skillsDir;
|
|
320
|
+
const result = await createService().uninstall('parkscan-skill', { force: true });
|
|
321
|
+
expect(result.success).toBe(true);
|
|
322
|
+
expect(result.warning).toContain('could not be listed (EACCES)');
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
describe('uninstall keeps the manifest honest (SMI-6529 round 16)', () => {
|
|
326
|
+
it('reports what an earlier removal left parked next to the skill', async () => {
|
|
327
|
+
const installPath = path.join(skillsDir, 'leftover-skill');
|
|
328
|
+
await fs.mkdir(installPath);
|
|
329
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
330
|
+
const parked = path.join(skillsDir, '.leftover-skill.skillsmith-removing-0123456789abcdef0123456789abcdef');
|
|
331
|
+
await fs.mkdir(parked);
|
|
332
|
+
await fs.writeFile(path.join(parked, 'part.md'), 'partial');
|
|
333
|
+
await track('leftover-skill', installPath);
|
|
334
|
+
const result = await createService().uninstall('leftover-skill', { force: true });
|
|
335
|
+
expect(result.success).toBe(true);
|
|
336
|
+
expect(result.warning).toContain(parked);
|
|
337
|
+
expect(result.warning).toContain('an interrupted removal');
|
|
338
|
+
// Round 18: the wording does not claim the parked entry is ours.
|
|
339
|
+
expect(result.warning).toContain('restore or delete it yourself');
|
|
340
|
+
expect(await fs.readFile(path.join(parked, 'part.md'), 'utf-8')).toBe('partial');
|
|
341
|
+
});
|
|
342
|
+
// Round 17 (cross-model review): the reinstall lands at the SAME path, so
|
|
343
|
+
// comparing paths alone would read it as the record just removed and delete
|
|
344
|
+
// the new install's record.
|
|
345
|
+
it('leaves the record alone when the same name is reinstalled at the same path', async () => {
|
|
346
|
+
const installPath = path.join(skillsDir, 'claimed-skill');
|
|
347
|
+
await fs.mkdir(installPath);
|
|
348
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
349
|
+
await track('claimed-skill', installPath);
|
|
350
|
+
claimOnRename.path = installPath;
|
|
351
|
+
claimOnRename.manifestPath = manifestPath;
|
|
352
|
+
claimOnRename.key = 'claimed-skill';
|
|
353
|
+
claimOnRename.newInstallPath = installPath;
|
|
354
|
+
claimOnRename.reinstalledAt = '2030-01-01T00:00:00.000Z';
|
|
355
|
+
const result = await createService().uninstall('claimed-skill', { force: true });
|
|
356
|
+
expect(result.success).toBe(true);
|
|
357
|
+
expect(result.warning).toContain('Another install claimed this name');
|
|
358
|
+
expect(await manifestEntry('claimed-skill')).toMatchObject({
|
|
359
|
+
installPath,
|
|
360
|
+
installedAt: '2030-01-01T00:00:00.000Z',
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
it('names what is parked even when the record could not be updated', async () => {
|
|
364
|
+
const installPath = path.join(skillsDir, 'stuck-parked');
|
|
365
|
+
await fs.mkdir(installPath);
|
|
366
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
367
|
+
const parked = path.join(skillsDir, '.stuck-parked.skillsmith-removing-0123456789abcdef0123456789abcdef');
|
|
368
|
+
await fs.mkdir(parked);
|
|
369
|
+
await fs.writeFile(path.join(parked, 'part.md'), 'partial');
|
|
370
|
+
await track('stuck-parked', installPath);
|
|
371
|
+
failRenameTo.path = manifestPath;
|
|
372
|
+
const result = await createService().uninstall('stuck-parked', { force: true });
|
|
373
|
+
expect(result.success).toBe(false);
|
|
374
|
+
expect(result.warning).toContain(parked);
|
|
375
|
+
});
|
|
376
|
+
it('says what to do when the folder is gone but its record could not be updated', async () => {
|
|
377
|
+
const installPath = path.join(skillsDir, 'stuck-skill');
|
|
378
|
+
await fs.mkdir(installPath);
|
|
379
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
380
|
+
await track('stuck-skill', installPath);
|
|
381
|
+
failRenameTo.path = manifestPath;
|
|
382
|
+
const result = await createService().uninstall('stuck-skill', { force: true });
|
|
383
|
+
expect(result.success).toBe(false);
|
|
384
|
+
expect(result.message).toContain('could not be updated');
|
|
385
|
+
expect(result.message).toContain(manifestPath);
|
|
386
|
+
expect(result.message).toContain('run the same remove again once that file is writable');
|
|
387
|
+
await expect(fs.lstat(installPath)).rejects.toMatchObject({ code: 'ENOENT' });
|
|
388
|
+
expect(await manifestEntry('stuck-skill')).toBeDefined();
|
|
389
|
+
});
|
|
390
|
+
// Round 18 (cross-model review): timestamps are not a unique generation
|
|
391
|
+
// token — two installs can share a millisecond, and an older writer omits
|
|
392
|
+
// them — so the whole record is compared.
|
|
393
|
+
it('leaves the record alone when a reinstall shares both timestamps', async () => {
|
|
394
|
+
const installPath = path.join(skillsDir, 'collide-skill');
|
|
395
|
+
await fs.mkdir(installPath);
|
|
396
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
397
|
+
await track('collide-skill', installPath);
|
|
398
|
+
claimOnRename.path = installPath;
|
|
399
|
+
claimOnRename.manifestPath = manifestPath;
|
|
400
|
+
claimOnRename.key = 'collide-skill';
|
|
401
|
+
claimOnRename.newVersion = '9.9.9';
|
|
402
|
+
const result = await createService().uninstall('collide-skill', { force: true });
|
|
403
|
+
expect(result.success).toBe(true);
|
|
404
|
+
expect(result.warning).toContain('Another install claimed this name');
|
|
405
|
+
expect(await manifestEntry('collide-skill')).toMatchObject({ version: '9.9.9' });
|
|
406
|
+
});
|
|
407
|
+
it('leaves the record alone when a record with no timestamps is replaced', async () => {
|
|
408
|
+
const installPath = path.join(skillsDir, 'legacy-skill');
|
|
409
|
+
await fs.mkdir(installPath);
|
|
410
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
411
|
+
await trackLegacy('legacy-skill', installPath);
|
|
412
|
+
const claimedPath = path.join(tmpDir, 'elsewhere', 'legacy-skill');
|
|
413
|
+
claimOnRename.path = installPath;
|
|
414
|
+
claimOnRename.manifestPath = manifestPath;
|
|
415
|
+
claimOnRename.key = 'legacy-skill';
|
|
416
|
+
claimOnRename.newInstallPath = claimedPath;
|
|
417
|
+
const result = await createService().uninstall('legacy-skill', { force: true });
|
|
418
|
+
expect(result.success).toBe(true);
|
|
419
|
+
expect(result.warning).toContain('Another install claimed this name');
|
|
420
|
+
expect(await manifestEntry('legacy-skill')).toMatchObject({ installPath: claimedPath });
|
|
421
|
+
});
|
|
422
|
+
// Round 19 (Opus): comparing field by field with `!==` was correct only
|
|
423
|
+
// while every field is a string. One array field, and the record would be
|
|
424
|
+
// kept forever with a warning saying an install claimed the name.
|
|
425
|
+
it('drops a record that carries a non-string field', async () => {
|
|
426
|
+
const installPath = path.join(skillsDir, 'tagged-skill');
|
|
427
|
+
await fs.mkdir(installPath);
|
|
428
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
429
|
+
await trackWithExtra('tagged-skill', installPath, ['one', 'two']);
|
|
430
|
+
const result = await createService().uninstall('tagged-skill', { force: true });
|
|
431
|
+
expect(result.success).toBe(true);
|
|
432
|
+
expect(result.warning ?? '').not.toContain('Another install claimed this name');
|
|
433
|
+
expect(await manifestEntry('tagged-skill')).toBeUndefined();
|
|
434
|
+
});
|
|
435
|
+
it('still reports what is parked when a progress listener throws', async () => {
|
|
436
|
+
const installPath = path.join(skillsDir, 'noisy-skill');
|
|
437
|
+
await fs.mkdir(installPath);
|
|
438
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
439
|
+
const parked = path.join(skillsDir, '.noisy-skill.skillsmith-removing-0123456789abcdef0123456789abcdef');
|
|
440
|
+
await fs.mkdir(parked);
|
|
441
|
+
await fs.writeFile(path.join(parked, 'part.md'), 'partial');
|
|
442
|
+
await track('noisy-skill', installPath);
|
|
443
|
+
const result = await createService(() => {
|
|
444
|
+
throw new Error('listener exploded');
|
|
445
|
+
}).uninstall('noisy-skill', { force: true });
|
|
446
|
+
expect(result.success).toBe(true);
|
|
447
|
+
expect(result.warning).toContain(parked);
|
|
448
|
+
await expect(fs.lstat(installPath)).rejects.toMatchObject({ code: 'ENOENT' });
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
describe('uninstall removes only the folder it checked (SMI-6529 round 15)', () => {
|
|
452
|
+
it('leaves a folder another program swapped in, and keeps the manifest entry', async () => {
|
|
453
|
+
const installPath = path.join(skillsDir, 'swapped-skill');
|
|
454
|
+
await fs.mkdir(installPath);
|
|
455
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), '# Installed\n');
|
|
456
|
+
await track('swapped-skill', installPath);
|
|
457
|
+
swapBeforeRename.path = installPath;
|
|
458
|
+
const result = await createService().uninstall('swapped-skill', { force: true });
|
|
459
|
+
expect(result.success).toBe(false);
|
|
460
|
+
expect(result.message).toMatch(/was not removed: .* was replaced by something else, and that entry is now at /);
|
|
461
|
+
// Round 17 (cross-model review): their folder is never renamed back over
|
|
462
|
+
// whatever is at the path now. It is moved aside, and the exact path is
|
|
463
|
+
// reported, so nothing of theirs is destroyed.
|
|
464
|
+
const parkedName = (await fs.readdir(skillsDir)).find((n) => n.startsWith('.swapped-skill.skillsmith-removing-'));
|
|
465
|
+
expect(parkedName).toBeDefined();
|
|
466
|
+
expect(await fs.readFile(path.join(skillsDir, parkedName ?? '', 'KEEP.md'), 'utf-8')).toBe('not ours');
|
|
467
|
+
expect(result.warning).toContain(parkedName ?? 'no parked entry');
|
|
468
|
+
// Our own copy is where their swap moved it, untouched.
|
|
469
|
+
expect(await fs.readFile(path.join(`${installPath}-moved`, 'SKILL.md'), 'utf-8')).toBe('# Installed\n');
|
|
470
|
+
expect(await manifestEntry('swapped-skill')).toBeDefined();
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
//# sourceMappingURL=skill-installation.uninstall.guard.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installation.uninstall.guard.test.js","sourceRoot":"","sources":["../../../../tests/unit/services/skill-installation.uninstall.guard.test.ts"],"names":[],"mappings":"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"}
|