@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-installation.io.js","sourceRoot":"","sources":["../../../src/services/skill-installation.io.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAA;AACjC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAC5B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"skill-installation.io.js","sourceRoot":"","sources":["../../../src/services/skill-installation.io.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview writeInstallFiles' file-level snapshot/restore rollback helpers.
|
|
3
|
+
* @module @skillsmith/core/services/skill-installation.io.rollback
|
|
4
|
+
* @see SMI-6529 Wave A0
|
|
5
|
+
*
|
|
6
|
+
* Split out of skill-installation.io.ts to stay under the 500-line CI gate
|
|
7
|
+
* once the rollback fix landed (mirrors this module's existing sibling-split
|
|
8
|
+
* convention, e.g. skill-installation.policy.ts).
|
|
9
|
+
*
|
|
10
|
+
* On a real user machine, a rollback in `writeInstallFiles` used to unlink
|
|
11
|
+
* every file it had touched — including files that ALREADY EXISTED before
|
|
12
|
+
* the install started (a real user's git-cloned skill directory, `.git`
|
|
13
|
+
* included). These helpers make that rollback safe: classify a file BEFORE
|
|
14
|
+
* writing into it, snapshot it if it's a pre-existing regular file, and
|
|
15
|
+
* restore it if the install fails partway through.
|
|
16
|
+
*
|
|
17
|
+
* F1 (review round 1): `safeWriteFile` opens with O_TRUNC and writes in
|
|
18
|
+
* place — not atomic. A write that fails mid-way (ENOSPC/EIO after
|
|
19
|
+
* truncation) can leave a truncated original on disk. The snapshot MUST be
|
|
20
|
+
* taken, and recorded as a rollback candidate, BEFORE `safeWriteFile` is
|
|
21
|
+
* ever called — never after it "succeeds," since a failure can occur after
|
|
22
|
+
* the file has already been truncated.
|
|
23
|
+
*/
|
|
24
|
+
import { type EntryIdentity } from '../install/remove-if-same.js';
|
|
25
|
+
/** A pre-write copy of a regular file (path, bytes and mode), used to restore it on rollback. */
|
|
26
|
+
export interface FileSnapshot {
|
|
27
|
+
path: string;
|
|
28
|
+
content: Buffer;
|
|
29
|
+
mode: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* SMI-6529 H2: thrown instead of a plain `Error` whenever a rollback restore
|
|
33
|
+
* fails partway through a failed (or later-cancelled) install — i.e. some
|
|
34
|
+
* pre-existing file could NOT be restored to its original content and the
|
|
35
|
+
* user needs to recover it manually. Before this class existed, the
|
|
36
|
+
* compound message ("Install failed (...) AND could not restore N
|
|
37
|
+
* pre-existing file(s)...") was a plain `Error`, so `sanitizeInstallError()`
|
|
38
|
+
* (skill-installation.helpers.ts) — which only passes through messages
|
|
39
|
+
* matching a small known-prefix allowlist — silently replaced this exact,
|
|
40
|
+
* actionable diagnostic with the generic "Installation failed due to an
|
|
41
|
+
* internal error", hiding the one failure mode where telling the user
|
|
42
|
+
* EXACTLY which files to recover manually matters most. `sanitizeInstallError`
|
|
43
|
+
* special-cases `instanceof InstallRestoreError` to always pass the message
|
|
44
|
+
* through verbatim, bypassing the allowlist entirely.
|
|
45
|
+
*/
|
|
46
|
+
export declare class InstallRestoreError extends Error {
|
|
47
|
+
/** The paths that could not be restored (same list as `restoreSnapshots()`'s return). */
|
|
48
|
+
readonly restoreFailures: string[];
|
|
49
|
+
/**
|
|
50
|
+
* SMI-6529 round 13: paths this install created but could not remove, each
|
|
51
|
+
* with its reason (a permission error, or a folder replaced by something
|
|
52
|
+
* else since the install created it). These used to be swallowed.
|
|
53
|
+
*/
|
|
54
|
+
readonly cleanupFailures: string[];
|
|
55
|
+
constructor(innerMessage: string, restoreFailures: string[], options?: {
|
|
56
|
+
cause?: unknown;
|
|
57
|
+
}, cleanupFailures?: string[]);
|
|
58
|
+
}
|
|
59
|
+
/** What {@link classifyPreWrite} found at a write target before any write. */
|
|
60
|
+
export type PreWriteClassification = {
|
|
61
|
+
kind: 'absent';
|
|
62
|
+
} | {
|
|
63
|
+
kind: 'regular';
|
|
64
|
+
snapshot: FileSnapshot;
|
|
65
|
+
}
|
|
66
|
+
/** Symlink, directory, or anything else `safeWriteFile` refuses BEFORE touching a byte. */
|
|
67
|
+
| {
|
|
68
|
+
kind: 'other';
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Classify a write target BEFORE any write is attempted, so the caller can
|
|
72
|
+
* record a rollback candidate (snapshot for an existing regular file, a
|
|
73
|
+
* fresh-creation marker for an absent path) ahead of the write — never
|
|
74
|
+
* after, since `safeWriteFile`'s O_TRUNC is not atomic and a failure can
|
|
75
|
+
* land between truncation and the write completing.
|
|
76
|
+
*/
|
|
77
|
+
export declare function classifyPreWrite(filePath: string): Promise<PreWriteClassification>;
|
|
78
|
+
/**
|
|
79
|
+
* Restore every overwritten file's original bytes + mode. Returns the paths
|
|
80
|
+
* that could NOT be restored rather than throwing — the caller must surface
|
|
81
|
+
* these explicitly (a failed restore is data loss the user needs to recover
|
|
82
|
+
* manually), never swallow them silently.
|
|
83
|
+
*
|
|
84
|
+
* F2 (review round 1):
|
|
85
|
+
* - Skips a no-op restore when the current bytes already equal the
|
|
86
|
+
* snapshot — avoids a false restore failure for a file `safeWriteFile`
|
|
87
|
+
* refused before ever touching it (e.g. a hardlinked file: snapshotted
|
|
88
|
+
* proactively per F1's "regular" classification, but never actually
|
|
89
|
+
* written, since `safeWriteFile`'s own hardlink check runs before any
|
|
90
|
+
* truncation).
|
|
91
|
+
* - Restores WITHOUT following symlinks: `open(O_WRONLY|O_TRUNC|O_NOFOLLOW)`
|
|
92
|
+
* + write + fd-level chmod — never a path-based `fs.writeFile`/`fs.chmod`,
|
|
93
|
+
* both of which follow symlinks and could write through one planted at
|
|
94
|
+
* the snapshot's path between snapshot-time and restore-time.
|
|
95
|
+
*
|
|
96
|
+
* SMI-6529 M4 (round 2): restores in REVERSE order (most-recently-taken
|
|
97
|
+
* snapshot first). This is the correct undo-stack semantics whenever two
|
|
98
|
+
* snapshots can legitimately describe the SAME real on-disk file at
|
|
99
|
+
* different points in time — e.g. a case-insensitive filesystem alias
|
|
100
|
+
* (`SKILL.md`/`skill.md` on default APFS) that this module's caller failed
|
|
101
|
+
* to dedupe: snapshot A ("before write 1") and snapshot B ("before write 2",
|
|
102
|
+
* captured AFTER write 1 already ran) both target the same inode. Restoring
|
|
103
|
+
* forward (A then B) ends on B's value — the intermediate post-write-1 state,
|
|
104
|
+
* not the true original. Restoring in reverse (B then A) always converges on
|
|
105
|
+
* the earliest, TRUE original. A caller that also dedupes at snapshot-time
|
|
106
|
+
* (as `writeInstallFiles` now does) never produces such a pair in the first
|
|
107
|
+
* place — this ordering is defense-in-depth for any snapshot list this
|
|
108
|
+
* function is ever handed, not a substitute for that dedupe.
|
|
109
|
+
*
|
|
110
|
+
* SMI-6529 N3 (round 4): writes via `writeFullBuffer()` (loops until every
|
|
111
|
+
* byte is written — `FileHandle.write()` can short-write without throwing,
|
|
112
|
+
* measured live under `RLIMIT_FSIZE`) and then verifies the ON-DISK size
|
|
113
|
+
* matches the snapshot's exact length before trusting the restore. Either
|
|
114
|
+
* check failing is treated as a restore FAILURE (pushed to `failures`, same
|
|
115
|
+
* as any other error here) — a partially-restored file is exactly the data
|
|
116
|
+
* loss this whole module exists to prevent, so it must never be reported as
|
|
117
|
+
* a clean restore.
|
|
118
|
+
*/
|
|
119
|
+
export declare function restoreSnapshots(snapshots: FileSnapshot[]): Promise<string[]>;
|
|
120
|
+
export type { EntryIdentity };
|
|
121
|
+
/**
|
|
122
|
+
* Run one rollback cleanup step. An error whose code is in `ignore` means
|
|
123
|
+
* nothing of ours was left to remove; any other is recorded in `failures`
|
|
124
|
+
* (path and reason) for the caller to report. SMI-6529 round 13
|
|
125
|
+
* (cross-model review): these were all swallowed, so a failed install could
|
|
126
|
+
* leave files behind without saying so.
|
|
127
|
+
*/
|
|
128
|
+
export declare function cleanupStep(target: string, step: () => Promise<void>, ignore: readonly string[], failures: string[]): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Recursively remove a directory this install created, but only while it is
|
|
131
|
+
* still that directory (same device and inode). If something else now sits
|
|
132
|
+
* at the path, it is left alone and recorded as a failure (round 13). Round
|
|
133
|
+
* 15: the entry is checked after it is parked under a random name
|
|
134
|
+
* (`removeIfSame`), so nothing can be swapped in between the check and the
|
|
135
|
+
* delete.
|
|
136
|
+
*/
|
|
137
|
+
export declare function removeCreatedDirectory(dir: string, identity: EntryIdentity | undefined, failures: string[]): Promise<void>;
|
|
138
|
+
//# sourceMappingURL=skill-installation.io.rollback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installation.io.rollback.d.ts","sourceRoot":"","sources":["../../../src/services/skill-installation.io.rollback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAKH,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAE/E,iGAAiG;AACjG,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,yFAAyF;IACzF,SAAgB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzC;;;;OAIG;IACH,SAAgB,eAAe,EAAE,MAAM,EAAE,CAAA;gBAGvC,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,EAAE,EACzB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAC7B,eAAe,GAAE,MAAM,EAAO;CA+BjC;AAED,8EAA8E;AAC9E,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAA;CAAE;AAC7C,2FAA2F;GACzF;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAA;AAErB;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAWxF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmCnF;AAED,YAAY,EAAE,aAAa,EAAE,CAAA;AAE7B;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EACzB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview writeInstallFiles' file-level snapshot/restore rollback helpers.
|
|
3
|
+
* @module @skillsmith/core/services/skill-installation.io.rollback
|
|
4
|
+
* @see SMI-6529 Wave A0
|
|
5
|
+
*
|
|
6
|
+
* Split out of skill-installation.io.ts to stay under the 500-line CI gate
|
|
7
|
+
* once the rollback fix landed (mirrors this module's existing sibling-split
|
|
8
|
+
* convention, e.g. skill-installation.policy.ts).
|
|
9
|
+
*
|
|
10
|
+
* On a real user machine, a rollback in `writeInstallFiles` used to unlink
|
|
11
|
+
* every file it had touched — including files that ALREADY EXISTED before
|
|
12
|
+
* the install started (a real user's git-cloned skill directory, `.git`
|
|
13
|
+
* included). These helpers make that rollback safe: classify a file BEFORE
|
|
14
|
+
* writing into it, snapshot it if it's a pre-existing regular file, and
|
|
15
|
+
* restore it if the install fails partway through.
|
|
16
|
+
*
|
|
17
|
+
* F1 (review round 1): `safeWriteFile` opens with O_TRUNC and writes in
|
|
18
|
+
* place — not atomic. A write that fails mid-way (ENOSPC/EIO after
|
|
19
|
+
* truncation) can leave a truncated original on disk. The snapshot MUST be
|
|
20
|
+
* taken, and recorded as a rollback candidate, BEFORE `safeWriteFile` is
|
|
21
|
+
* ever called — never after it "succeeds," since a failure can occur after
|
|
22
|
+
* the file has already been truncated.
|
|
23
|
+
*/
|
|
24
|
+
import * as fs from 'fs/promises';
|
|
25
|
+
import { constants } from 'fs';
|
|
26
|
+
import { O_NOFOLLOW, writeFullBuffer } from '../utils/safe-fs.js';
|
|
27
|
+
import { removeIfSame } from '../install/remove-if-same.js';
|
|
28
|
+
/**
|
|
29
|
+
* SMI-6529 H2: thrown instead of a plain `Error` whenever a rollback restore
|
|
30
|
+
* fails partway through a failed (or later-cancelled) install — i.e. some
|
|
31
|
+
* pre-existing file could NOT be restored to its original content and the
|
|
32
|
+
* user needs to recover it manually. Before this class existed, the
|
|
33
|
+
* compound message ("Install failed (...) AND could not restore N
|
|
34
|
+
* pre-existing file(s)...") was a plain `Error`, so `sanitizeInstallError()`
|
|
35
|
+
* (skill-installation.helpers.ts) — which only passes through messages
|
|
36
|
+
* matching a small known-prefix allowlist — silently replaced this exact,
|
|
37
|
+
* actionable diagnostic with the generic "Installation failed due to an
|
|
38
|
+
* internal error", hiding the one failure mode where telling the user
|
|
39
|
+
* EXACTLY which files to recover manually matters most. `sanitizeInstallError`
|
|
40
|
+
* special-cases `instanceof InstallRestoreError` to always pass the message
|
|
41
|
+
* through verbatim, bypassing the allowlist entirely.
|
|
42
|
+
*/
|
|
43
|
+
export class InstallRestoreError extends Error {
|
|
44
|
+
/** The paths that could not be restored (same list as `restoreSnapshots()`'s return). */
|
|
45
|
+
restoreFailures;
|
|
46
|
+
/**
|
|
47
|
+
* SMI-6529 round 13: paths this install created but could not remove, each
|
|
48
|
+
* with its reason (a permission error, or a folder replaced by something
|
|
49
|
+
* else since the install created it). These used to be swallowed.
|
|
50
|
+
*/
|
|
51
|
+
cleanupFailures;
|
|
52
|
+
constructor(innerMessage, restoreFailures, options, cleanupFailures = []) {
|
|
53
|
+
const parts = [];
|
|
54
|
+
if (restoreFailures.length > 0) {
|
|
55
|
+
parts.push('could not restore ' +
|
|
56
|
+
restoreFailures.length +
|
|
57
|
+
' pre-existing file(s) to their original content: ' +
|
|
58
|
+
restoreFailures.join(', '));
|
|
59
|
+
}
|
|
60
|
+
if (cleanupFailures.length > 0) {
|
|
61
|
+
parts.push('could not remove ' +
|
|
62
|
+
cleanupFailures.length +
|
|
63
|
+
' path(s) it created: ' +
|
|
64
|
+
cleanupFailures.join(', '));
|
|
65
|
+
}
|
|
66
|
+
super('Install failed (' +
|
|
67
|
+
innerMessage +
|
|
68
|
+
') AND ' +
|
|
69
|
+
parts.join(' AND ') +
|
|
70
|
+
'. Recover these manually before retrying.', options);
|
|
71
|
+
this.name = 'InstallRestoreError';
|
|
72
|
+
this.restoreFailures = restoreFailures;
|
|
73
|
+
this.cleanupFailures = cleanupFailures;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Classify a write target BEFORE any write is attempted, so the caller can
|
|
78
|
+
* record a rollback candidate (snapshot for an existing regular file, a
|
|
79
|
+
* fresh-creation marker for an absent path) ahead of the write — never
|
|
80
|
+
* after, since `safeWriteFile`'s O_TRUNC is not atomic and a failure can
|
|
81
|
+
* land between truncation and the write completing.
|
|
82
|
+
*/
|
|
83
|
+
export async function classifyPreWrite(filePath) {
|
|
84
|
+
let stat;
|
|
85
|
+
try {
|
|
86
|
+
stat = await fs.lstat(filePath);
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
if (err.code === 'ENOENT')
|
|
90
|
+
return { kind: 'absent' };
|
|
91
|
+
throw err;
|
|
92
|
+
}
|
|
93
|
+
if (!stat.isFile())
|
|
94
|
+
return { kind: 'other' };
|
|
95
|
+
const content = await fs.readFile(filePath);
|
|
96
|
+
return { kind: 'regular', snapshot: { path: filePath, content, mode: stat.mode } };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Restore every overwritten file's original bytes + mode. Returns the paths
|
|
100
|
+
* that could NOT be restored rather than throwing — the caller must surface
|
|
101
|
+
* these explicitly (a failed restore is data loss the user needs to recover
|
|
102
|
+
* manually), never swallow them silently.
|
|
103
|
+
*
|
|
104
|
+
* F2 (review round 1):
|
|
105
|
+
* - Skips a no-op restore when the current bytes already equal the
|
|
106
|
+
* snapshot — avoids a false restore failure for a file `safeWriteFile`
|
|
107
|
+
* refused before ever touching it (e.g. a hardlinked file: snapshotted
|
|
108
|
+
* proactively per F1's "regular" classification, but never actually
|
|
109
|
+
* written, since `safeWriteFile`'s own hardlink check runs before any
|
|
110
|
+
* truncation).
|
|
111
|
+
* - Restores WITHOUT following symlinks: `open(O_WRONLY|O_TRUNC|O_NOFOLLOW)`
|
|
112
|
+
* + write + fd-level chmod — never a path-based `fs.writeFile`/`fs.chmod`,
|
|
113
|
+
* both of which follow symlinks and could write through one planted at
|
|
114
|
+
* the snapshot's path between snapshot-time and restore-time.
|
|
115
|
+
*
|
|
116
|
+
* SMI-6529 M4 (round 2): restores in REVERSE order (most-recently-taken
|
|
117
|
+
* snapshot first). This is the correct undo-stack semantics whenever two
|
|
118
|
+
* snapshots can legitimately describe the SAME real on-disk file at
|
|
119
|
+
* different points in time — e.g. a case-insensitive filesystem alias
|
|
120
|
+
* (`SKILL.md`/`skill.md` on default APFS) that this module's caller failed
|
|
121
|
+
* to dedupe: snapshot A ("before write 1") and snapshot B ("before write 2",
|
|
122
|
+
* captured AFTER write 1 already ran) both target the same inode. Restoring
|
|
123
|
+
* forward (A then B) ends on B's value — the intermediate post-write-1 state,
|
|
124
|
+
* not the true original. Restoring in reverse (B then A) always converges on
|
|
125
|
+
* the earliest, TRUE original. A caller that also dedupes at snapshot-time
|
|
126
|
+
* (as `writeInstallFiles` now does) never produces such a pair in the first
|
|
127
|
+
* place — this ordering is defense-in-depth for any snapshot list this
|
|
128
|
+
* function is ever handed, not a substitute for that dedupe.
|
|
129
|
+
*
|
|
130
|
+
* SMI-6529 N3 (round 4): writes via `writeFullBuffer()` (loops until every
|
|
131
|
+
* byte is written — `FileHandle.write()` can short-write without throwing,
|
|
132
|
+
* measured live under `RLIMIT_FSIZE`) and then verifies the ON-DISK size
|
|
133
|
+
* matches the snapshot's exact length before trusting the restore. Either
|
|
134
|
+
* check failing is treated as a restore FAILURE (pushed to `failures`, same
|
|
135
|
+
* as any other error here) — a partially-restored file is exactly the data
|
|
136
|
+
* loss this whole module exists to prevent, so it must never be reported as
|
|
137
|
+
* a clean restore.
|
|
138
|
+
*/
|
|
139
|
+
export async function restoreSnapshots(snapshots) {
|
|
140
|
+
const failures = [];
|
|
141
|
+
for (const snapshot of [...snapshots].reverse()) {
|
|
142
|
+
try {
|
|
143
|
+
let current;
|
|
144
|
+
try {
|
|
145
|
+
current = await fs.readFile(snapshot.path);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
current = null;
|
|
149
|
+
}
|
|
150
|
+
if (current !== null && current.equals(snapshot.content)) {
|
|
151
|
+
continue; // already matches — nothing was actually written here
|
|
152
|
+
}
|
|
153
|
+
const handle = await fs.open(snapshot.path, constants.O_WRONLY | constants.O_TRUNC | O_NOFOLLOW);
|
|
154
|
+
try {
|
|
155
|
+
await writeFullBuffer(handle, snapshot.content, 0);
|
|
156
|
+
const finalStat = await handle.stat();
|
|
157
|
+
if (finalStat.size !== snapshot.content.length) {
|
|
158
|
+
throw new Error(`Restore incomplete: wrote ${finalStat.size} of ${snapshot.content.length} bytes`);
|
|
159
|
+
}
|
|
160
|
+
await handle.chmod(snapshot.mode);
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
await handle.close();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
failures.push(snapshot.path);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return failures;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Run one rollback cleanup step. An error whose code is in `ignore` means
|
|
174
|
+
* nothing of ours was left to remove; any other is recorded in `failures`
|
|
175
|
+
* (path and reason) for the caller to report. SMI-6529 round 13
|
|
176
|
+
* (cross-model review): these were all swallowed, so a failed install could
|
|
177
|
+
* leave files behind without saying so.
|
|
178
|
+
*/
|
|
179
|
+
export async function cleanupStep(target, step, ignore, failures) {
|
|
180
|
+
try {
|
|
181
|
+
await step();
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
const code = err.code;
|
|
185
|
+
if (code !== undefined && ignore.includes(code))
|
|
186
|
+
return;
|
|
187
|
+
failures.push(`${target} (${code ?? (err instanceof Error ? err.message : String(err))})`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Recursively remove a directory this install created, but only while it is
|
|
192
|
+
* still that directory (same device and inode). If something else now sits
|
|
193
|
+
* at the path, it is left alone and recorded as a failure (round 13). Round
|
|
194
|
+
* 15: the entry is checked after it is parked under a random name
|
|
195
|
+
* (`removeIfSame`), so nothing can be swapped in between the check and the
|
|
196
|
+
* delete.
|
|
197
|
+
*/
|
|
198
|
+
export async function removeCreatedDirectory(dir, identity, failures) {
|
|
199
|
+
if (identity === undefined) {
|
|
200
|
+
// The install never recorded what it created, so nothing shows that
|
|
201
|
+
// what is at the path now is ours.
|
|
202
|
+
try {
|
|
203
|
+
await fs.lstat(dir);
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
if (err.code === 'ENOENT')
|
|
207
|
+
return;
|
|
208
|
+
failures.push(`${dir} (${err.code ?? String(err)})`);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
failures.push(`${dir} (replaced by something else after the install created it; left in place)`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const removal = await removeIfSame(dir, identity);
|
|
215
|
+
if (!removal.removed)
|
|
216
|
+
failures.push(`${dir} (${removal.reason})`);
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=skill-installation.io.rollback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installation.io.rollback.js","sourceRoot":"","sources":["../../../src/services/skill-installation.io.rollback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview writeInstallFiles() — the disk-write + rollback core of skill install.
|
|
3
|
+
* @module @skillsmith/core/services/skill-installation.io.write
|
|
4
|
+
* @see SMI-6529 Wave A0 round 2: split out of skill-installation.io.ts to stay
|
|
5
|
+
* under the 500-line CI gate once the M4/M7/M10/L14/L15 fixes landed — pure
|
|
6
|
+
* move for everything that predates this split, no behavior change to it.
|
|
7
|
+
* Re-exported from skill-installation.io.ts so every existing
|
|
8
|
+
* `from './skill-installation.io.js'` import site is unaffected.
|
|
9
|
+
* @see SMI-6529 round 4 (N1/N2/N8/N9/N11/N12): confirmation-review fixes —
|
|
10
|
+
* see each inline comment below for the specific finding it closes.
|
|
11
|
+
*/
|
|
12
|
+
import { type ClientId } from '../install/paths.js';
|
|
13
|
+
/** What {@link writeInstallFiles} wrote, plus a `rollback` that undoes it. */
|
|
14
|
+
export interface WriteInstallResult {
|
|
15
|
+
writtenFiles: string[];
|
|
16
|
+
subagentPath?: string;
|
|
17
|
+
/**
|
|
18
|
+
* SMI-6529 M10: true when a companion agent file was NOT written because
|
|
19
|
+
* this was a FRESH install (`preExisted` false) and something already
|
|
20
|
+
* occupied the companion-agent target path — a pre-existing file there
|
|
21
|
+
* could belong to an unrelated skill/agent the user created by hand, so a
|
|
22
|
+
* brand-new install must never silently overwrite it. A forced reinstall
|
|
23
|
+
* of an already-tracked skill (`preExisted` true) still overwrites it, on
|
|
24
|
+
* the theory that Skillsmith itself most likely generated it originally.
|
|
25
|
+
*/
|
|
26
|
+
companionSkipped?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* SMI-6529 M7: restores every file this call overwrote to its pre-install
|
|
29
|
+
* bytes/mode and removes everything it created fresh — the SAME cleanup
|
|
30
|
+
* `writeInstallFiles` runs on its own internal write failure, exposed so a
|
|
31
|
+
* caller whose LATER step fails (e.g. the manifest update in
|
|
32
|
+
* `finalizeSuccessfulInstall`) can undo a write that itself already
|
|
33
|
+
* succeeded. Pass the causing error so a restore failure can be reported
|
|
34
|
+
* alongside it via {@link InstallRestoreError}; on a clean restore this
|
|
35
|
+
* resolves without throwing and the caller should rethrow its own error.
|
|
36
|
+
*/
|
|
37
|
+
rollback: (causeError: unknown) => Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Write a skill's files into `installPath`, snapshotting every file it will
|
|
41
|
+
* overwrite first. On failure it restores those files and removes only what
|
|
42
|
+
* it created; a directory that existed before the call is never removed.
|
|
43
|
+
* Callers run `checkInstallTarget` first.
|
|
44
|
+
*/
|
|
45
|
+
export declare function writeInstallFiles(installPath: string, skillsDir: string, skillName: string, finalSkillContent: string, subSkillFiles: Array<{
|
|
46
|
+
filename: string;
|
|
47
|
+
content: string;
|
|
48
|
+
}>, subagentContent: string | undefined,
|
|
49
|
+
/**
|
|
50
|
+
* SMI-5980 (Wave 3): the client this companion subagent (if any) is
|
|
51
|
+
* generated for — resolves its output path via
|
|
52
|
+
* `resolveCompanionAgentPath()` (install/paths.ts) instead of a hardcoded
|
|
53
|
+
* `~/.claude/agents/` literal. Optional, defaulting to `CANONICAL_CLIENT`
|
|
54
|
+
* (`claude-code`) so pre-existing callers/tests that never pass it keep
|
|
55
|
+
* today's exact behavior unchanged.
|
|
56
|
+
*/
|
|
57
|
+
client?: ClientId,
|
|
58
|
+
/**
|
|
59
|
+
* SMI-5982 code-review fix #1: explicit base dir for resolving a RELATIVE
|
|
60
|
+
* `COMPANION_AGENT_TARGETS[client].dir` (Antigravity only — every other
|
|
61
|
+
* client's `dir` is absolute already). Threaded through to
|
|
62
|
+
* `resolveCompanionAgentPath()`'s own `baseDir` param as-is (no
|
|
63
|
+
* `?? process.cwd()` fallback here) — `resolveCompanionAgentPath()` itself
|
|
64
|
+
* now requires an explicit `baseDir` for every `directory-package`-mode
|
|
65
|
+
* client (PR-review follow-up), so whether an omitted `companionBaseDir`
|
|
66
|
+
* is acceptable is that function's call to make, not this one's.
|
|
67
|
+
*/
|
|
68
|
+
companionBaseDir?: string): Promise<WriteInstallResult>;
|
|
69
|
+
//# sourceMappingURL=skill-installation.io.write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installation.io.write.d.ts","sourceRoot":"","sources":["../../../src/services/skill-installation.io.write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAIL,KAAK,QAAQ,EACd,MAAM,qBAAqB,CAAA;AAe5B,8EAA8E;AAC9E,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B;;;;;;;;;OASG;IACH,QAAQ,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACjD;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,EACzB,aAAa,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,EAC3D,eAAe,EAAE,MAAM,GAAG,SAAS;AACnC;;;;;;;GAOG;AACH,MAAM,GAAE,QAA2B;AACnC;;;;;;;;;GASG;AACH,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,kBAAkB,CAAC,CAgZ7B"}
|