safeword 0.74.3 → 0.74.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/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/codex-plugin/hooks.json +5 -5
- package/dist/{architecture-ZM6AM3AZ.js → architecture-I5I63ODT.js} +2 -2
- package/dist/{architecture-document-Q3LWXN3U.js → architecture-document-HD3YGB6N.js} +2 -2
- package/dist/{architecture-monorepo-U4G4Y4RC.js → architecture-monorepo-YLM3QZRC.js} +2 -2
- package/dist/{boundary-TPREVQVV.js → boundary-YHU7JNQP.js} +5 -5
- package/dist/{chunk-RHIDFAQA.js → chunk-2PS33UXO.js} +2 -2
- package/dist/chunk-4HQHVNDP.js +445 -0
- package/dist/chunk-4HQHVNDP.js.map +1 -0
- package/dist/{chunk-FTYPJREM.js → chunk-4OFXUDHH.js} +23 -16
- package/dist/chunk-4OFXUDHH.js.map +1 -0
- package/dist/{chunk-MXY37UIE.js → chunk-5LY4CXG6.js} +5 -5
- package/dist/chunk-6ORAURPL.js +51 -0
- package/dist/chunk-6ORAURPL.js.map +1 -0
- package/dist/chunk-7OZGZQUA.js +1209 -0
- package/dist/chunk-7OZGZQUA.js.map +1 -0
- package/dist/chunk-BTY7MFRX.js +122 -0
- package/dist/chunk-BTY7MFRX.js.map +1 -0
- package/dist/{chunk-LWQ5Y74H.js → chunk-HVYKVVCW.js} +3 -3
- package/dist/chunk-JVZIT7JQ.js +37 -0
- package/dist/chunk-JVZIT7JQ.js.map +1 -0
- package/dist/{chunk-F35EZZZT.js → chunk-KD5NAIPO.js} +58 -58
- package/dist/chunk-KD5NAIPO.js.map +1 -0
- package/dist/{chunk-XWT7EZLO.js → chunk-KFN7EUCQ.js} +3 -3
- package/dist/{chunk-KUBO23BM.js → chunk-LDPULEYD.js} +2 -2
- package/dist/{chunk-KUBO23BM.js.map → chunk-LDPULEYD.js.map} +1 -1
- package/dist/{chunk-JOY2KXC2.js → chunk-NR6NOK4M.js} +4 -4
- package/dist/chunk-OCXDMJQA.js +94 -0
- package/dist/chunk-OCXDMJQA.js.map +1 -0
- package/dist/{chunk-7HASZNFI.js → chunk-P2S7FQRA.js} +39 -30
- package/dist/chunk-P2S7FQRA.js.map +1 -0
- package/dist/{chunk-UTO5XZ4S.js → chunk-QOLHGAD5.js} +30 -1
- package/dist/chunk-QOLHGAD5.js.map +1 -0
- package/dist/{chunk-6ASDB62E.js → chunk-TZL5PTPF.js} +2 -2
- package/dist/{chunk-IELT2VNA.js → chunk-WDV6JDUK.js} +80 -55
- package/dist/chunk-WDV6JDUK.js.map +1 -0
- package/dist/cleanup-FPBQLZ2F.js +21 -0
- package/dist/cleanup-command-QZE2NUEO.js +140 -0
- package/dist/cleanup-command-QZE2NUEO.js.map +1 -0
- package/dist/cli.js +58 -58
- package/dist/cli.js.map +1 -1
- package/dist/{clients-BOFXTO5I.js → clients-6GGYBIIT.js} +2 -2
- package/dist/{codex-bootstrap-MGOXLYXJ.js → codex-bootstrap-MVNK3CJX.js} +8 -7
- package/dist/{codex-bootstrap-MGOXLYXJ.js.map → codex-bootstrap-MVNK3CJX.js.map} +1 -1
- package/dist/{codex-hook-CFMEGJCN.js → codex-hook-B4T2LNIM.js} +6 -5
- package/dist/{codex-hook-CFMEGJCN.js.map → codex-hook-B4T2LNIM.js.map} +1 -1
- package/dist/{codify-KJT5NVB5.js → codify-YMWHM43R.js} +2 -2
- package/dist/{commands-VSLOQTWF.js → commands-VEPXV3A5.js} +44 -22
- package/dist/commands-VEPXV3A5.js.map +1 -0
- package/dist/{config-K6YMTMBZ.js → config-WU66XLLM.js} +2 -2
- package/dist/{configured-paths-TNT5ES6B.js → configured-paths-KYHGU76W.js} +2 -2
- package/dist/{contract-O3IPB22M.js → contract-NMP7CNSE.js} +2 -2
- package/dist/{coordinator-HCFO5Q5U.js → coordinator-SH4E2T6G.js} +2 -2
- package/dist/{corpus-H6VAZQ2C.js → corpus-YCAJ7VOZ.js} +2 -2
- package/dist/{doctor-LZI5WHAL.js → doctor-MLMTY4RQ.js} +13 -9
- package/dist/{doctor-LZI5WHAL.js.map → doctor-MLMTY4RQ.js.map} +1 -1
- package/dist/{feature-directories-GJSVN6EV.js → feature-directories-Y42M6ZPU.js} +2 -2
- package/dist/{finalization-2UYMPEKI.js → finalization-6Z24HKM3.js} +4 -4
- package/dist/{gh-cli-PDCMBXIG.js → gh-cli-LUTM2W24.js} +2 -2
- package/dist/{github-rest-LYWIBF22.js → github-rest-4C2AMOLE.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{learning-sync-VTAQWVFW.js → learning-sync-3BHPGBWQ.js} +2 -2
- package/dist/{legacy-global-guidance-HCINJ4C2.js → legacy-global-guidance-ZI4UYW7D.js} +2 -2
- package/dist/{lint-gherkin-VHEI2HQB.js → lint-gherkin-KYCAT2YG.js} +2 -2
- package/dist/{operations-S2HHRITZ.js → operations-Y3Q7Z6UN.js} +8 -7
- package/dist/{output-2FJMIY3V.js → output-EFMGKKFW.js} +2 -2
- package/dist/presets/typescript/index.js +1 -1
- package/dist/{profile-QWFJPPE3.js → profile-KZ2IF7P7.js} +10 -7
- package/dist/{prompt-AIF6X5SI.js → prompt-UXFDHQMS.js} +2 -2
- package/dist/{remove-EKFEKH5M.js → remove-E475NLRE.js} +6 -5
- package/dist/{retro-LSPXAALQ.js → retro-YI4JK6A6.js} +8 -8
- package/dist/{retro-draft-spool-ONRCYA4T.js → retro-draft-spool-XF5V3RTQ.js} +2 -2
- package/dist/{retro-extract-SZVL3WMR.js → retro-extract-NCIF3FZQ.js} +2 -2
- package/dist/{review-pr-YMDEAMKY.js → review-pr-TGVWLVWS.js} +2 -2
- package/dist/{review-pr-publication-MUOMVPUS.js → review-pr-publication-LDXXFOLW.js} +2 -2
- package/dist/{run-HHXCVFEQ.js → run-QGTCEUV3.js} +2 -2
- package/dist/{self-report-TDWLZCLT.js → self-report-SXYHNLMI.js} +2 -2
- package/dist/status-4F3W6S3O.js +25 -0
- package/dist/{status-XUOSLCWP.js → status-KDUZCYQZ.js} +13 -9
- package/dist/{sync-config-3HLU4Q2R.js → sync-config-KQUXF6OV.js} +2 -2
- package/dist/{sync-tracker-OROZET3U.js → sync-tracker-ULCYB7DU.js} +2 -2
- package/dist/{test-plan-7K5BXV55.js → test-plan-ORLLL5PC.js} +2 -2
- package/dist/{ticket-new-IC2RTCYH.js → ticket-new-B23JRB3X.js} +2 -2
- package/dist/{ticket-sync-VKJTHNU5.js → ticket-sync-J65H63QY.js} +2 -2
- package/dist/{tracker-map-X5IVIIBU.js → tracker-map-UTEDGSW6.js} +2 -2
- package/dist/{tracker-sync-NIPDWB6P.js → tracker-sync-2LUPWR5T.js} +2 -2
- package/dist/tracker-sync-2LUPWR5T.js.map +1 -0
- package/package.json +5 -1
- package/templates/hooks/stop-quality.ts +68 -47
- package/dist/chunk-7HASZNFI.js.map +0 -1
- package/dist/chunk-F35EZZZT.js.map +0 -1
- package/dist/chunk-FTYPJREM.js.map +0 -1
- package/dist/chunk-IELT2VNA.js.map +0 -1
- package/dist/chunk-LHUJKQLV.js +0 -16
- package/dist/chunk-LHUJKQLV.js.map +0 -1
- package/dist/chunk-UTO5XZ4S.js.map +0 -1
- package/dist/cleanup-NUD7IBRU.js +0 -307
- package/dist/cleanup-NUD7IBRU.js.map +0 -1
- package/dist/commands-VSLOQTWF.js.map +0 -1
- package/dist/status-JOZSPPKE.js +0 -20
- /package/dist/{architecture-ZM6AM3AZ.js.map → architecture-I5I63ODT.js.map} +0 -0
- /package/dist/{architecture-document-Q3LWXN3U.js.map → architecture-document-HD3YGB6N.js.map} +0 -0
- /package/dist/{architecture-monorepo-U4G4Y4RC.js.map → architecture-monorepo-YLM3QZRC.js.map} +0 -0
- /package/dist/{boundary-TPREVQVV.js.map → boundary-YHU7JNQP.js.map} +0 -0
- /package/dist/{chunk-RHIDFAQA.js.map → chunk-2PS33UXO.js.map} +0 -0
- /package/dist/{chunk-MXY37UIE.js.map → chunk-5LY4CXG6.js.map} +0 -0
- /package/dist/{chunk-LWQ5Y74H.js.map → chunk-HVYKVVCW.js.map} +0 -0
- /package/dist/{chunk-XWT7EZLO.js.map → chunk-KFN7EUCQ.js.map} +0 -0
- /package/dist/{chunk-JOY2KXC2.js.map → chunk-NR6NOK4M.js.map} +0 -0
- /package/dist/{chunk-6ASDB62E.js.map → chunk-TZL5PTPF.js.map} +0 -0
- /package/dist/{clients-BOFXTO5I.js.map → cleanup-FPBQLZ2F.js.map} +0 -0
- /package/dist/{config-K6YMTMBZ.js.map → clients-6GGYBIIT.js.map} +0 -0
- /package/dist/{codify-KJT5NVB5.js.map → codify-YMWHM43R.js.map} +0 -0
- /package/dist/{configured-paths-TNT5ES6B.js.map → config-WU66XLLM.js.map} +0 -0
- /package/dist/{corpus-H6VAZQ2C.js.map → configured-paths-KYHGU76W.js.map} +0 -0
- /package/dist/{contract-O3IPB22M.js.map → contract-NMP7CNSE.js.map} +0 -0
- /package/dist/{coordinator-HCFO5Q5U.js.map → coordinator-SH4E2T6G.js.map} +0 -0
- /package/dist/{finalization-2UYMPEKI.js.map → corpus-YCAJ7VOZ.js.map} +0 -0
- /package/dist/{feature-directories-GJSVN6EV.js.map → feature-directories-Y42M6ZPU.js.map} +0 -0
- /package/dist/{gh-cli-PDCMBXIG.js.map → finalization-6Z24HKM3.js.map} +0 -0
- /package/dist/{legacy-global-guidance-HCINJ4C2.js.map → gh-cli-LUTM2W24.js.map} +0 -0
- /package/dist/{github-rest-LYWIBF22.js.map → github-rest-4C2AMOLE.js.map} +0 -0
- /package/dist/{learning-sync-VTAQWVFW.js.map → learning-sync-3BHPGBWQ.js.map} +0 -0
- /package/dist/{operations-S2HHRITZ.js.map → legacy-global-guidance-ZI4UYW7D.js.map} +0 -0
- /package/dist/{lint-gherkin-VHEI2HQB.js.map → lint-gherkin-KYCAT2YG.js.map} +0 -0
- /package/dist/{output-2FJMIY3V.js.map → operations-Y3Q7Z6UN.js.map} +0 -0
- /package/dist/{profile-QWFJPPE3.js.map → output-EFMGKKFW.js.map} +0 -0
- /package/dist/{prompt-AIF6X5SI.js.map → profile-KZ2IF7P7.js.map} +0 -0
- /package/dist/{remove-EKFEKH5M.js.map → prompt-UXFDHQMS.js.map} +0 -0
- /package/dist/{retro-draft-spool-ONRCYA4T.js.map → remove-E475NLRE.js.map} +0 -0
- /package/dist/{retro-LSPXAALQ.js.map → retro-YI4JK6A6.js.map} +0 -0
- /package/dist/{retro-extract-SZVL3WMR.js.map → retro-draft-spool-XF5V3RTQ.js.map} +0 -0
- /package/dist/{self-report-TDWLZCLT.js.map → retro-extract-NCIF3FZQ.js.map} +0 -0
- /package/dist/{review-pr-YMDEAMKY.js.map → review-pr-TGVWLVWS.js.map} +0 -0
- /package/dist/{review-pr-publication-MUOMVPUS.js.map → review-pr-publication-LDXXFOLW.js.map} +0 -0
- /package/dist/{run-HHXCVFEQ.js.map → run-QGTCEUV3.js.map} +0 -0
- /package/dist/{status-JOZSPPKE.js.map → self-report-SXYHNLMI.js.map} +0 -0
- /package/dist/{status-XUOSLCWP.js.map → status-4F3W6S3O.js.map} +0 -0
- /package/dist/{sync-config-3HLU4Q2R.js.map → status-KDUZCYQZ.js.map} +0 -0
- /package/dist/{ticket-sync-VKJTHNU5.js.map → sync-config-KQUXF6OV.js.map} +0 -0
- /package/dist/{sync-tracker-OROZET3U.js.map → sync-tracker-ULCYB7DU.js.map} +0 -0
- /package/dist/{test-plan-7K5BXV55.js.map → test-plan-ORLLL5PC.js.map} +0 -0
- /package/dist/{ticket-new-IC2RTCYH.js.map → ticket-new-B23JRB3X.js.map} +0 -0
- /package/dist/{tracker-map-X5IVIIBU.js.map → ticket-sync-J65H63QY.js.map} +0 -0
- /package/dist/{tracker-sync-NIPDWB6P.js.map → tracker-map-UTEDGSW6.js.map} +0 -0
package/codex-plugin/hooks.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"hooks": [
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
9
|
-
"command": "bunx --bun safeword@0.74.
|
|
9
|
+
"command": "bunx --bun safeword@0.74.4 hook codex session-start --plugin-hook",
|
|
10
10
|
"timeout": 120,
|
|
11
11
|
"statusMessage": "Loading Safe Word standing instructions"
|
|
12
12
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"hooks": [
|
|
20
20
|
{
|
|
21
21
|
"type": "command",
|
|
22
|
-
"command": "bunx --bun safeword@0.74.
|
|
22
|
+
"command": "bunx --bun safeword@0.74.4 hook codex pre-tool-use --plugin-hook",
|
|
23
23
|
"timeout": 30,
|
|
24
24
|
"statusMessage": "Checking Safe Word edit gates"
|
|
25
25
|
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"hooks": [
|
|
33
33
|
{
|
|
34
34
|
"type": "command",
|
|
35
|
-
"command": "bunx --bun safeword@0.74.
|
|
35
|
+
"command": "bunx --bun safeword@0.74.4 hook codex post-tool-use --plugin-hook",
|
|
36
36
|
"timeout": 30,
|
|
37
37
|
"statusMessage": "Surfacing Safe Word post-tool context"
|
|
38
38
|
}
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"hooks": [
|
|
46
46
|
{
|
|
47
47
|
"type": "command",
|
|
48
|
-
"command": "bunx --bun safeword@0.74.
|
|
48
|
+
"command": "bunx --bun safeword@0.74.4 hook codex user-prompt-submit --plugin-hook",
|
|
49
49
|
"timeout": 30,
|
|
50
50
|
"statusMessage": "Checking queued Safe Word prompt context"
|
|
51
51
|
}
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"hooks": [
|
|
59
59
|
{
|
|
60
60
|
"type": "command",
|
|
61
|
-
"command": "bunx --bun safeword@0.74.
|
|
61
|
+
"command": "bunx --bun safeword@0.74.4 hook codex stop --plugin-hook",
|
|
62
62
|
"timeout": 600,
|
|
63
63
|
"statusMessage": "Checking Safe Word stop continuation"
|
|
64
64
|
}
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
readJson,
|
|
26
26
|
writeJson
|
|
27
27
|
} from "./chunk-7G6OSNIV.js";
|
|
28
|
-
import "./chunk-
|
|
28
|
+
import "./chunk-LDPULEYD.js";
|
|
29
29
|
|
|
30
30
|
// src/commands/architecture.ts
|
|
31
31
|
import { execFileSync } from "child_process";
|
|
@@ -650,4 +650,4 @@ export {
|
|
|
650
650
|
architectureStage,
|
|
651
651
|
architectureStaged
|
|
652
652
|
};
|
|
653
|
-
//# sourceMappingURL=architecture-
|
|
653
|
+
//# sourceMappingURL=architecture-I5I63ODT.js.map
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import "./chunk-YP2V3YUV.js";
|
|
12
12
|
import "./chunk-2MI7M2CO.js";
|
|
13
13
|
import "./chunk-7G6OSNIV.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-LDPULEYD.js";
|
|
15
15
|
export {
|
|
16
16
|
isSafewordOwned,
|
|
17
17
|
isWouldChangeAction,
|
|
@@ -22,4 +22,4 @@ export {
|
|
|
22
22
|
selfHealProject,
|
|
23
23
|
selfHealProjectPreservingProse
|
|
24
24
|
};
|
|
25
|
-
//# sourceMappingURL=architecture-document-
|
|
25
|
+
//# sourceMappingURL=architecture-document-HD3YGB6N.js.map
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
monorepoFingerprintOf
|
|
6
6
|
} from "./chunk-YP2V3YUV.js";
|
|
7
7
|
import "./chunk-7G6OSNIV.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-LDPULEYD.js";
|
|
9
9
|
export {
|
|
10
10
|
discoverUnreadableWorkspaces,
|
|
11
11
|
discoverWorkspaces,
|
|
12
12
|
extractMonorepoArchitectureSnapshot,
|
|
13
13
|
monorepoFingerprintOf
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=architecture-monorepo-
|
|
15
|
+
//# sourceMappingURL=architecture-monorepo-YLM3QZRC.js.map
|
|
@@ -5,15 +5,15 @@ import {
|
|
|
5
5
|
parseImplPlan,
|
|
6
6
|
scalar
|
|
7
7
|
} from "./chunk-SPK32BMX.js";
|
|
8
|
+
import {
|
|
9
|
+
createPhaseAnchorScope
|
|
10
|
+
} from "./chunk-K64BTVJ7.js";
|
|
8
11
|
import {
|
|
9
12
|
classifyAnnotation,
|
|
10
13
|
isValidSha,
|
|
11
14
|
isValidSkipReason,
|
|
12
15
|
parseCheckboxAnnotation
|
|
13
16
|
} from "./chunk-Z4ESH6KU.js";
|
|
14
|
-
import {
|
|
15
|
-
createPhaseAnchorScope
|
|
16
|
-
} from "./chunk-K64BTVJ7.js";
|
|
17
17
|
import "./chunk-URVJZ4NL.js";
|
|
18
18
|
import {
|
|
19
19
|
warn
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
import {
|
|
26
26
|
readFileSafe
|
|
27
27
|
} from "./chunk-7G6OSNIV.js";
|
|
28
|
-
import "./chunk-
|
|
28
|
+
import "./chunk-LDPULEYD.js";
|
|
29
29
|
|
|
30
30
|
// src/commands/boundary.ts
|
|
31
31
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
@@ -628,4 +628,4 @@ function boundary(options) {
|
|
|
628
628
|
export {
|
|
629
629
|
boundary
|
|
630
630
|
};
|
|
631
|
-
//# sourceMappingURL=boundary-
|
|
631
|
+
//# sourceMappingURL=boundary-YHU7JNQP.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
durableRename,
|
|
3
3
|
writeDurableFile
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QOLHGAD5.js";
|
|
5
5
|
import {
|
|
6
6
|
CODEX_MIGRATION_SCHEMA
|
|
7
7
|
} from "./chunk-XHNWNZRM.js";
|
|
@@ -479,4 +479,4 @@ export {
|
|
|
479
479
|
observeCodexRecoveryPlan,
|
|
480
480
|
applyCodexFinalization
|
|
481
481
|
};
|
|
482
|
-
//# sourceMappingURL=chunk-
|
|
482
|
+
//# sourceMappingURL=chunk-2PS33UXO.js.map
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canonicalClaudeProjectRoot
|
|
3
|
+
} from "./chunk-JVZIT7JQ.js";
|
|
4
|
+
import {
|
|
5
|
+
advisoryStateDigest,
|
|
6
|
+
claudeWatchedSettingsDigest,
|
|
7
|
+
createClaudePluginMode,
|
|
8
|
+
writeClaudeMigrationAttention,
|
|
9
|
+
writeClaudePluginMode
|
|
10
|
+
} from "./chunk-OCXDMJQA.js";
|
|
11
|
+
import {
|
|
12
|
+
assertSafeClaudeCleanupTarget,
|
|
13
|
+
containedClaudeCleanupPath,
|
|
14
|
+
observeClaudeLegacy
|
|
15
|
+
} from "./chunk-BTY7MFRX.js";
|
|
16
|
+
import {
|
|
17
|
+
CLAUDE_MIGRATION_SCHEMA
|
|
18
|
+
} from "./chunk-6ORAURPL.js";
|
|
19
|
+
import {
|
|
20
|
+
writeDurableFile,
|
|
21
|
+
writeDurableFileExclusive
|
|
22
|
+
} from "./chunk-QOLHGAD5.js";
|
|
23
|
+
import {
|
|
24
|
+
createResult
|
|
25
|
+
} from "./chunk-6Z2GFE27.js";
|
|
26
|
+
|
|
27
|
+
// src/claude-plugin/cleanup.ts
|
|
28
|
+
import { createHash, randomUUID } from "crypto";
|
|
29
|
+
import {
|
|
30
|
+
chmodSync,
|
|
31
|
+
existsSync,
|
|
32
|
+
lstatSync,
|
|
33
|
+
mkdirSync,
|
|
34
|
+
readdirSync,
|
|
35
|
+
readFileSync,
|
|
36
|
+
rmdirSync,
|
|
37
|
+
rmSync
|
|
38
|
+
} from "fs";
|
|
39
|
+
import nodePath from "path";
|
|
40
|
+
import { applyEdits, modify, parse, visit } from "jsonc-parser";
|
|
41
|
+
function sha256(content) {
|
|
42
|
+
return createHash("sha256").update(content).digest("hex");
|
|
43
|
+
}
|
|
44
|
+
function containsJsonComments(content) {
|
|
45
|
+
let found = false;
|
|
46
|
+
visit(content, { onComment: () => found = true });
|
|
47
|
+
return found;
|
|
48
|
+
}
|
|
49
|
+
function settingsMutation(cwd, legacy) {
|
|
50
|
+
const relative = ".claude/settings.json";
|
|
51
|
+
const path = nodePath.join(cwd, relative);
|
|
52
|
+
if (!existsSync(path) || legacy.recognizedHooks.length === 0) return void 0;
|
|
53
|
+
const original = readFileSync(path, "utf8");
|
|
54
|
+
const parsed = parse(original);
|
|
55
|
+
const hooks = parsed.hooks ?? {};
|
|
56
|
+
const allHookValuesAreArrays = Object.values(hooks).every((entries) => Array.isArray(entries));
|
|
57
|
+
const hookCount = Object.values(hooks).reduce(
|
|
58
|
+
(count, entries) => count + (Array.isArray(entries) ? entries.length : 0),
|
|
59
|
+
0
|
|
60
|
+
);
|
|
61
|
+
const generatedHookOnlyFile = Object.keys(parsed).length === 1 && allHookValuesAreArrays && hookCount === legacy.recognizedHooks.length && !containsJsonComments(original);
|
|
62
|
+
if (generatedHookOnlyFile) return { path: relative, content: null };
|
|
63
|
+
let content = original;
|
|
64
|
+
const references = legacy.recognizedHooks.toSorted((left, right) => {
|
|
65
|
+
const eventOrder = right.event.localeCompare(left.event);
|
|
66
|
+
return eventOrder === 0 ? right.index - left.index : eventOrder;
|
|
67
|
+
});
|
|
68
|
+
for (const reference of references) {
|
|
69
|
+
content = applyEdits(
|
|
70
|
+
content,
|
|
71
|
+
modify(content, ["hooks", reference.event, reference.index], void 0, {
|
|
72
|
+
formattingOptions: { insertSpaces: true, tabSize: 2 }
|
|
73
|
+
})
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
path: relative,
|
|
78
|
+
content
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function claudeLegacyMutations(cwd) {
|
|
82
|
+
const legacy = observeClaudeLegacy(cwd);
|
|
83
|
+
const files = legacy.recognizedFiles.map((path) => ({
|
|
84
|
+
path,
|
|
85
|
+
content: null
|
|
86
|
+
}));
|
|
87
|
+
const settings = settingsMutation(cwd, legacy);
|
|
88
|
+
if (settings !== void 0) files.push(settings);
|
|
89
|
+
return files;
|
|
90
|
+
}
|
|
91
|
+
function claudeCleanupPreconditionDigest(cwd, mutations) {
|
|
92
|
+
return sha256(
|
|
93
|
+
JSON.stringify(
|
|
94
|
+
mutations.map((mutation) => {
|
|
95
|
+
const target = assertSafeClaudeCleanupTarget(cwd, mutation.path);
|
|
96
|
+
return [mutation.path, sha256(readFileSync(target)), mutation.content];
|
|
97
|
+
})
|
|
98
|
+
)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
function transactionPath(cwd) {
|
|
102
|
+
return containedClaudeCleanupPath(cwd, CLAUDE_MIGRATION_SCHEMA.paths.transaction);
|
|
103
|
+
}
|
|
104
|
+
function writeTransaction(cwd, transaction) {
|
|
105
|
+
const path = transactionPath(cwd);
|
|
106
|
+
mkdirSync(nodePath.dirname(path), { recursive: true, mode: 448 });
|
|
107
|
+
writeDurableFileExclusive(path, `${JSON.stringify(transaction, void 0, 2)}
|
|
108
|
+
`, {
|
|
109
|
+
mode: 384
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function entryFor(cwd, mutation) {
|
|
113
|
+
const path = assertSafeClaudeCleanupTarget(cwd, mutation.path);
|
|
114
|
+
const before = readFileSync(path);
|
|
115
|
+
const after = mutation.content === null ? null : Buffer.from(mutation.content);
|
|
116
|
+
return {
|
|
117
|
+
path: mutation.path,
|
|
118
|
+
before_sha256: sha256(before),
|
|
119
|
+
before_base64: before.toString("base64"),
|
|
120
|
+
before_mode: lstatSync(path).mode & 511,
|
|
121
|
+
after_sha256: after === null ? null : sha256(after),
|
|
122
|
+
after_base64: after === null ? null : after.toString("base64"),
|
|
123
|
+
after_mode: after === null ? null : lstatSync(path).mode & 511
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function observedSha(path) {
|
|
127
|
+
return existsSync(path) ? sha256(readFileSync(path)) : null;
|
|
128
|
+
}
|
|
129
|
+
function pruneEmptyAncestors(root, path) {
|
|
130
|
+
const canonicalRoot = nodePath.resolve(root);
|
|
131
|
+
let directory = nodePath.dirname(nodePath.resolve(path));
|
|
132
|
+
while (directory.startsWith(`${canonicalRoot}${nodePath.sep}`)) {
|
|
133
|
+
try {
|
|
134
|
+
if (readdirSync(directory).length > 0) return;
|
|
135
|
+
rmdirSync(directory);
|
|
136
|
+
} catch {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
directory = nodePath.dirname(directory);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function writeImage(root, path, content, mode) {
|
|
143
|
+
if (content === null) {
|
|
144
|
+
rmSync(path, { force: true });
|
|
145
|
+
pruneEmptyAncestors(root, path);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
mkdirSync(nodePath.dirname(path), { recursive: true });
|
|
149
|
+
writeDurableFile(path, Buffer.from(content, "base64"), { mode: mode ?? 420 });
|
|
150
|
+
chmodSync(path, mode ?? 420);
|
|
151
|
+
}
|
|
152
|
+
function applyEntries(cwd, entries, shouldDefer = () => false) {
|
|
153
|
+
for (const entry of entries) {
|
|
154
|
+
if (shouldDefer()) return false;
|
|
155
|
+
const path = assertSafeClaudeCleanupTarget(cwd, entry.path);
|
|
156
|
+
if (observedSha(path) !== entry.before_sha256) {
|
|
157
|
+
throw new Error(`Claude cleanup target changed after planning: ${entry.path}`);
|
|
158
|
+
}
|
|
159
|
+
writeImage(cwd, path, entry.after_base64, entry.after_mode);
|
|
160
|
+
}
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
function writePluginModeMarker(cwd, transactionId) {
|
|
164
|
+
const marker = containedClaudeCleanupPath(cwd, CLAUDE_MIGRATION_SCHEMA.paths.pluginMarker);
|
|
165
|
+
mkdirSync(nodePath.dirname(marker), { recursive: true });
|
|
166
|
+
writeDurableFile(
|
|
167
|
+
marker,
|
|
168
|
+
`${JSON.stringify({ schema_version: 1, mode: "plugin", transaction_id: transactionId })}
|
|
169
|
+
`,
|
|
170
|
+
{ mode: 384 }
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
function unresolvedPaths(legacy) {
|
|
174
|
+
return [
|
|
175
|
+
...legacy.conflictingFiles,
|
|
176
|
+
...legacy.conflictingHooks.map(
|
|
177
|
+
(hook) => `.claude/settings.json#hooks.${hook.event}[${String(hook.index)}]`
|
|
178
|
+
),
|
|
179
|
+
...legacy.settingsError === void 0 ? [] : [".claude/settings.json"]
|
|
180
|
+
];
|
|
181
|
+
}
|
|
182
|
+
function automaticAdvisory(paths) {
|
|
183
|
+
if (paths.length === 0) return void 0;
|
|
184
|
+
return `Safeword removed the old Claude integration it could verify, but preserved unrecognized content at ${paths.join(", ")}. Review those paths; your prompt was not blocked.`;
|
|
185
|
+
}
|
|
186
|
+
function recordAutomaticAttention(cwd, options, classification, advisory) {
|
|
187
|
+
writeClaudeMigrationAttention(cwd, {
|
|
188
|
+
schema_version: 1,
|
|
189
|
+
state_digest: advisoryStateDigest(advisory),
|
|
190
|
+
plugin_version: options.pluginVersion,
|
|
191
|
+
catalogue_sha256: options.catalogueSha256,
|
|
192
|
+
watched_settings_sha256: claudeWatchedSettingsDigest(cwd),
|
|
193
|
+
classification,
|
|
194
|
+
advisory
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function waitForPluginMode(cwd, deadline, now) {
|
|
198
|
+
const marker = containedClaudeCleanupPath(cwd, CLAUDE_MIGRATION_SCHEMA.paths.pluginMarkerV2);
|
|
199
|
+
const pause = new Int32Array(new SharedArrayBuffer(4));
|
|
200
|
+
const maximumChecks = 25;
|
|
201
|
+
for (let checks = 0; checks < maximumChecks && now() < deadline; checks += 1) {
|
|
202
|
+
if (existsSync(marker)) return true;
|
|
203
|
+
const remaining = Math.max(1, deadline - now());
|
|
204
|
+
Atomics.wait(pause, 0, 0, Math.min(20, remaining));
|
|
205
|
+
}
|
|
206
|
+
return existsSync(marker);
|
|
207
|
+
}
|
|
208
|
+
function writeAutomaticPluginMode(cwd, transaction) {
|
|
209
|
+
const pluginMode = transaction.plugin_mode;
|
|
210
|
+
if (pluginMode === void 0) {
|
|
211
|
+
writePluginModeMarker(cwd, transaction.transaction_id);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
writeClaudePluginMode(
|
|
215
|
+
cwd,
|
|
216
|
+
createClaudePluginMode({
|
|
217
|
+
plugin_version: pluginMode.plugin_version,
|
|
218
|
+
hook_manifest_sha256: pluginMode.hook_manifest_sha256,
|
|
219
|
+
catalogue_sha256: pluginMode.catalogue_sha256,
|
|
220
|
+
unresolved_paths: pluginMode.unresolved_paths,
|
|
221
|
+
advisory: pluginMode.advisory,
|
|
222
|
+
transaction_id: transaction.transaction_id
|
|
223
|
+
})
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
function cleanupFailure(error, classification = "coexistence") {
|
|
227
|
+
return createResult({
|
|
228
|
+
state: "failed",
|
|
229
|
+
errors: [{ code: "CLAUDE_CLEANUP_FAILED", message: String(error), retryable: true }],
|
|
230
|
+
nextActions: [{ command: "safeword claude recover", mutates: true, requiresHuman: true }],
|
|
231
|
+
data: { command: "claude cleanup", classification }
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
function migrateClaudeLegacyAutomatically(cwd, options) {
|
|
235
|
+
const now = options.now ?? Date.now;
|
|
236
|
+
let projectRoot;
|
|
237
|
+
try {
|
|
238
|
+
projectRoot = canonicalClaudeProjectRoot(cwd);
|
|
239
|
+
return performAutomaticMigration(projectRoot, options, now);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
const advisory = `Safeword preserved the old Claude integration after cleanup could not finish: ${error instanceof Error ? error.message : String(error)} Your prompt was not blocked; run \`safeword claude recover\` to repair it.`;
|
|
242
|
+
if (projectRoot !== void 0) {
|
|
243
|
+
try {
|
|
244
|
+
recordAutomaticAttention(projectRoot, options, "migration-error", advisory);
|
|
245
|
+
} catch {
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
state: "attention",
|
|
250
|
+
advisory,
|
|
251
|
+
unresolvedPaths: []
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function recoveredAutomaticResult(projectRoot) {
|
|
256
|
+
const recovered = recoverClaudeCleanup(projectRoot);
|
|
257
|
+
if (recovered.state !== "failed") return { state: "complete", unresolvedPaths: [] };
|
|
258
|
+
const detail = recovered.errors?.[0]?.message ?? "the recorded cleanup transaction could not be read safely";
|
|
259
|
+
return {
|
|
260
|
+
state: "attention",
|
|
261
|
+
advisory: `Safeword preserved the old Claude integration because automatic recovery could not finish: ${detail} Your prompt was not blocked; run \`safeword claude recover\` to repair it.`,
|
|
262
|
+
unresolvedPaths: []
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function writeObservedPluginMode(projectRoot, options, unresolved, advisory) {
|
|
266
|
+
writeClaudePluginMode(
|
|
267
|
+
projectRoot,
|
|
268
|
+
createClaudePluginMode({
|
|
269
|
+
plugin_version: options.pluginVersion,
|
|
270
|
+
hook_manifest_sha256: options.hookManifestSha256,
|
|
271
|
+
catalogue_sha256: options.catalogueSha256,
|
|
272
|
+
unresolved_paths: unresolved,
|
|
273
|
+
advisory
|
|
274
|
+
})
|
|
275
|
+
);
|
|
276
|
+
return { state: "complete", advisory, unresolvedPaths: unresolved };
|
|
277
|
+
}
|
|
278
|
+
function claimAutomaticTransaction(projectRoot, transaction, options, now, unresolved) {
|
|
279
|
+
try {
|
|
280
|
+
writeTransaction(projectRoot, transaction);
|
|
281
|
+
return void 0;
|
|
282
|
+
} catch (error) {
|
|
283
|
+
if (error.code !== "EEXIST") throw error;
|
|
284
|
+
if (waitForPluginMode(projectRoot, options.deadline, now)) {
|
|
285
|
+
return { state: "complete", unresolvedPaths: unresolved };
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
state: "deferred",
|
|
289
|
+
advisory: "Another Safeword process is retiring the old Claude integration. Your prompt was not blocked; the next prompt will verify that it finished.",
|
|
290
|
+
unresolvedPaths: unresolved
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function concurrentMigrationResult(projectRoot, options, now) {
|
|
295
|
+
const concurrentDeadline = Math.min(options.deadline, now() + 500);
|
|
296
|
+
if (waitForPluginMode(projectRoot, concurrentDeadline, now)) {
|
|
297
|
+
return { state: "complete", unresolvedPaths: [] };
|
|
298
|
+
}
|
|
299
|
+
if (now() >= options.deadline) {
|
|
300
|
+
return {
|
|
301
|
+
state: "deferred",
|
|
302
|
+
advisory: "Another Safeword process is retiring the old Claude integration. Your prompt was not blocked; the next prompt will verify that it finished.",
|
|
303
|
+
unresolvedPaths: []
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
return recoveredAutomaticResult(projectRoot);
|
|
307
|
+
}
|
|
308
|
+
function planCleanupEntries(projectRoot, mutations) {
|
|
309
|
+
try {
|
|
310
|
+
return mutations.map((mutation) => entryFor(projectRoot, mutation));
|
|
311
|
+
} catch (error) {
|
|
312
|
+
if (existsSync(transactionPath(projectRoot))) return void 0;
|
|
313
|
+
throw error;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function performAutomaticMigration(projectRoot, options, now) {
|
|
317
|
+
if (now() >= options.deadline) {
|
|
318
|
+
return {
|
|
319
|
+
state: "deferred",
|
|
320
|
+
advisory: "Safeword deferred old Claude integration cleanup until the next prompt.",
|
|
321
|
+
unresolvedPaths: []
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (existsSync(transactionPath(projectRoot)))
|
|
325
|
+
return concurrentMigrationResult(projectRoot, options, now);
|
|
326
|
+
const legacy = observeClaudeLegacy(projectRoot);
|
|
327
|
+
const unresolved = unresolvedPaths(legacy);
|
|
328
|
+
const advisory = automaticAdvisory(unresolved);
|
|
329
|
+
const mutations = claudeLegacyMutations(projectRoot);
|
|
330
|
+
if (mutations.length === 0) {
|
|
331
|
+
return writeObservedPluginMode(projectRoot, options, unresolved, advisory);
|
|
332
|
+
}
|
|
333
|
+
const entries = planCleanupEntries(projectRoot, mutations);
|
|
334
|
+
if (entries === void 0) return concurrentMigrationResult(projectRoot, options, now);
|
|
335
|
+
const transaction = {
|
|
336
|
+
schema_version: 1,
|
|
337
|
+
transaction_id: randomUUID(),
|
|
338
|
+
disposition: "complete-forward",
|
|
339
|
+
entries,
|
|
340
|
+
plugin_mode: {
|
|
341
|
+
plugin_version: options.pluginVersion,
|
|
342
|
+
hook_manifest_sha256: options.hookManifestSha256,
|
|
343
|
+
catalogue_sha256: options.catalogueSha256,
|
|
344
|
+
unresolved_paths: unresolved,
|
|
345
|
+
advisory
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
const contention = claimAutomaticTransaction(projectRoot, transaction, options, now, unresolved);
|
|
349
|
+
if (contention !== void 0) return contention;
|
|
350
|
+
if (!applyEntries(projectRoot, transaction.entries, () => now() >= options.deadline)) {
|
|
351
|
+
return {
|
|
352
|
+
state: "deferred",
|
|
353
|
+
advisory: "Safeword will finish removing its old Claude integration on the next prompt.",
|
|
354
|
+
unresolvedPaths: unresolved
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
writeAutomaticPluginMode(projectRoot, transaction);
|
|
358
|
+
rmSync(transactionPath(projectRoot), { force: true });
|
|
359
|
+
return { state: "complete", advisory, unresolvedPaths: unresolved };
|
|
360
|
+
}
|
|
361
|
+
function parseTransaction(cwd) {
|
|
362
|
+
const value = JSON.parse(readFileSync(transactionPath(cwd), "utf8"));
|
|
363
|
+
if (value.schema_version !== 1 || !Array.isArray(value.entries))
|
|
364
|
+
throw new Error("Claude cleanup transaction is malformed.");
|
|
365
|
+
return value;
|
|
366
|
+
}
|
|
367
|
+
function pendingRecoveryEntries(projectRoot, transaction) {
|
|
368
|
+
const forward = transaction.disposition === "complete-forward";
|
|
369
|
+
const pending = [];
|
|
370
|
+
for (const entry of transaction.entries) {
|
|
371
|
+
const path = assertSafeClaudeCleanupTarget(projectRoot, entry.path);
|
|
372
|
+
const current = observedSha(path);
|
|
373
|
+
const source = forward ? entry.before_sha256 : entry.after_sha256;
|
|
374
|
+
const destination = forward ? entry.after_sha256 : entry.before_sha256;
|
|
375
|
+
if (current === destination) continue;
|
|
376
|
+
if (current !== source) throw new Error(`Claude recovery conflict at ${entry.path}`);
|
|
377
|
+
pending.push(entry);
|
|
378
|
+
}
|
|
379
|
+
return pending;
|
|
380
|
+
}
|
|
381
|
+
function applyRecoveryEntries(projectRoot, transaction, pending) {
|
|
382
|
+
const forward = transaction.disposition === "complete-forward";
|
|
383
|
+
for (const entry of pending) {
|
|
384
|
+
const path = containedClaudeCleanupPath(projectRoot, entry.path);
|
|
385
|
+
writeImage(
|
|
386
|
+
projectRoot,
|
|
387
|
+
path,
|
|
388
|
+
forward ? entry.after_base64 : entry.before_base64,
|
|
389
|
+
forward ? entry.after_mode : entry.before_mode
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function completedRecoveryResult(projectRoot, transaction) {
|
|
394
|
+
if (transaction.disposition === "complete-forward") {
|
|
395
|
+
writeAutomaticPluginMode(projectRoot, transaction);
|
|
396
|
+
}
|
|
397
|
+
rmSync(transactionPath(projectRoot), { force: true });
|
|
398
|
+
return createResult({
|
|
399
|
+
state: "changed",
|
|
400
|
+
data: {
|
|
401
|
+
command: "claude recover",
|
|
402
|
+
classification: transaction.disposition === "complete-forward" ? "plugin-mode" : "cleanup-ready"
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
function recoverClaudeCleanup(cwd) {
|
|
407
|
+
let projectRoot;
|
|
408
|
+
try {
|
|
409
|
+
projectRoot = canonicalClaudeProjectRoot(cwd);
|
|
410
|
+
} catch (error) {
|
|
411
|
+
return cleanupFailure(error, "recovery-required");
|
|
412
|
+
}
|
|
413
|
+
if (!existsSync(transactionPath(projectRoot))) {
|
|
414
|
+
return createResult({
|
|
415
|
+
state: "healthy",
|
|
416
|
+
data: { command: "claude recover", classification: "plugin-mode" }
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
try {
|
|
420
|
+
const transaction = parseTransaction(projectRoot);
|
|
421
|
+
applyRecoveryEntries(
|
|
422
|
+
projectRoot,
|
|
423
|
+
transaction,
|
|
424
|
+
pendingRecoveryEntries(projectRoot, transaction)
|
|
425
|
+
);
|
|
426
|
+
return completedRecoveryResult(projectRoot, transaction);
|
|
427
|
+
} catch (error) {
|
|
428
|
+
return createResult({
|
|
429
|
+
state: "failed",
|
|
430
|
+
errors: [{ code: "CLAUDE_RECOVERY_CONFLICT", message: String(error), retryable: true }],
|
|
431
|
+
nextActions: [
|
|
432
|
+
{ command: "resolve the reported recovery conflict", mutates: false, requiresHuman: true }
|
|
433
|
+
],
|
|
434
|
+
data: { command: "claude recover", classification: "recovery-required" }
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export {
|
|
440
|
+
claudeLegacyMutations,
|
|
441
|
+
claudeCleanupPreconditionDigest,
|
|
442
|
+
migrateClaudeLegacyAutomatically,
|
|
443
|
+
recoverClaudeCleanup
|
|
444
|
+
};
|
|
445
|
+
//# sourceMappingURL=chunk-4HQHVNDP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/claude-plugin/cleanup.ts"],"sourcesContent":["/* eslint-disable unicorn/no-null -- null is the versioned absent-file image */\n\nimport { createHash, randomUUID } from 'node:crypto';\nimport {\n chmodSync,\n existsSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n rmdirSync,\n rmSync,\n} from 'node:fs';\nimport nodePath from 'node:path';\n\nimport { applyEdits, modify, parse, visit } from 'jsonc-parser';\n\nimport { type CliResult, createResult } from '../cli-protocol/result.js';\nimport { writeDurableFile, writeDurableFileExclusive } from '../codex-plugin/durable-write.js';\nimport { assertSafeClaudeCleanupTarget, containedClaudeCleanupPath } from './cleanup-target.js';\nimport { CLAUDE_MIGRATION_SCHEMA } from './inventory.js';\nimport { type ClaudeLegacyObservation, observeClaudeLegacy } from './legacy-classifier.js';\nimport {\n advisoryStateDigest,\n claudeWatchedSettingsDigest,\n createClaudePluginMode,\n writeClaudeMigrationAttention,\n writeClaudePluginMode,\n} from './migration-state.js';\nimport { canonicalClaudeProjectRoot } from './project-root.js';\n\ninterface CleanupEntry {\n readonly path: string;\n readonly before_sha256: string;\n readonly before_base64: string;\n readonly before_mode: number;\n readonly after_sha256: string | null;\n readonly after_base64: string | null;\n readonly after_mode: number | null;\n}\n\ninterface CleanupTransaction {\n readonly schema_version: 1;\n readonly transaction_id: string;\n readonly disposition: 'complete-forward' | 'restore-backup';\n readonly entries: CleanupEntry[];\n readonly plugin_mode?: {\n readonly plugin_version: string;\n readonly hook_manifest_sha256: string;\n readonly catalogue_sha256: string;\n readonly unresolved_paths: readonly string[];\n readonly advisory?: string;\n };\n}\n\nexport interface AutomaticClaudeMigrationOptions {\n readonly pluginVersion: string;\n readonly hookManifestSha256: string;\n readonly catalogueSha256: string;\n readonly deadline: number;\n readonly now?: () => number;\n}\n\nexport interface AutomaticClaudeMigrationResult {\n readonly state: 'complete' | 'deferred' | 'attention';\n readonly advisory?: string;\n readonly unresolvedPaths: readonly string[];\n}\n\nfunction sha256(content: Buffer | string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nfunction containsJsonComments(content: string): boolean {\n let found = false;\n visit(content, { onComment: () => (found = true) });\n return found;\n}\n\nfunction settingsMutation(\n cwd: string,\n legacy: ClaudeLegacyObservation,\n): { path: string; content: string | null } | undefined {\n const relative = '.claude/settings.json';\n const path = nodePath.join(cwd, relative);\n if (!existsSync(path) || legacy.recognizedHooks.length === 0) return undefined;\n const original = readFileSync(path, 'utf8');\n const parsed = parse(original) as Record<string, unknown>;\n const hooks = (parsed.hooks as Record<string, unknown[]> | undefined) ?? {};\n const allHookValuesAreArrays = Object.values(hooks).every(entries => Array.isArray(entries));\n const hookCount = Object.values(hooks).reduce(\n (count, entries) => count + (Array.isArray(entries) ? entries.length : 0),\n 0,\n );\n const generatedHookOnlyFile =\n Object.keys(parsed).length === 1 &&\n allHookValuesAreArrays &&\n hookCount === legacy.recognizedHooks.length &&\n !containsJsonComments(original);\n if (generatedHookOnlyFile) return { path: relative, content: null };\n\n let content = original;\n const references = legacy.recognizedHooks.toSorted((left, right) => {\n const eventOrder = right.event.localeCompare(left.event);\n return eventOrder === 0 ? right.index - left.index : eventOrder;\n });\n for (const reference of references) {\n content = applyEdits(\n content,\n modify(content, ['hooks', reference.event, reference.index], undefined, {\n formattingOptions: { insertSpaces: true, tabSize: 2 },\n }),\n );\n }\n return {\n path: relative,\n content,\n };\n}\n\nexport function claudeLegacyMutations(cwd: string): { path: string; content: string | null }[] {\n const legacy = observeClaudeLegacy(cwd);\n const files: { path: string; content: string | null }[] = legacy.recognizedFiles.map(path => ({\n path,\n content: null,\n }));\n const settings = settingsMutation(cwd, legacy);\n if (settings !== undefined) files.push(settings);\n return files;\n}\n\nexport function claudeCleanupPreconditionDigest(\n cwd: string,\n mutations: readonly { path: string; content: string | null }[],\n): string {\n return sha256(\n JSON.stringify(\n mutations.map(mutation => {\n const target = assertSafeClaudeCleanupTarget(cwd, mutation.path);\n return [mutation.path, sha256(readFileSync(target)), mutation.content];\n }),\n ),\n );\n}\n\nfunction transactionPath(cwd: string): string {\n return containedClaudeCleanupPath(cwd, CLAUDE_MIGRATION_SCHEMA.paths.transaction);\n}\n\nfunction writeTransaction(cwd: string, transaction: CleanupTransaction): void {\n const path = transactionPath(cwd);\n mkdirSync(nodePath.dirname(path), { recursive: true, mode: 0o700 });\n writeDurableFileExclusive(path, `${JSON.stringify(transaction, undefined, 2)}\\n`, {\n mode: 0o600,\n });\n}\n\nfunction entryFor(cwd: string, mutation: { path: string; content: string | null }): CleanupEntry {\n const path = assertSafeClaudeCleanupTarget(cwd, mutation.path);\n const before = readFileSync(path);\n const after = mutation.content === null ? null : Buffer.from(mutation.content);\n return {\n path: mutation.path,\n before_sha256: sha256(before),\n before_base64: before.toString('base64'),\n before_mode: lstatSync(path).mode & 0o777,\n after_sha256: after === null ? null : sha256(after),\n after_base64: after === null ? null : after.toString('base64'),\n after_mode: after === null ? null : lstatSync(path).mode & 0o777,\n };\n}\n\nfunction observedSha(path: string): string | null {\n return existsSync(path) ? sha256(readFileSync(path)) : null;\n}\n\n/**\n * Removes the directories a contracted file leaves behind. Legacy Claude\n * delivery is nested (`.claude/skills/<skill>/SKILL.md`), so deleting the files\n * alone strands a husk tree the user then has to clean up by hand. Pruning\n * stops at the first non-empty ancestor and never leaves the project root, so\n * it can only ever remove directories Safeword just emptied.\n */\nfunction pruneEmptyAncestors(root: string, path: string): void {\n const canonicalRoot = nodePath.resolve(root);\n let directory = nodePath.dirname(nodePath.resolve(path));\n while (directory.startsWith(`${canonicalRoot}${nodePath.sep}`)) {\n try {\n if (readdirSync(directory).length > 0) return;\n rmdirSync(directory);\n } catch {\n // A concurrent writer repopulated or removed the directory. The files\n // Safeword owns are already gone, so the prompt must not fail for a husk.\n return;\n }\n directory = nodePath.dirname(directory);\n }\n}\n\nfunction writeImage(root: string, path: string, content: string | null, mode: number | null): void {\n if (content === null) {\n rmSync(path, { force: true });\n pruneEmptyAncestors(root, path);\n return;\n }\n mkdirSync(nodePath.dirname(path), { recursive: true });\n writeDurableFile(path, Buffer.from(content, 'base64'), { mode: mode ?? 0o644 });\n chmodSync(path, mode ?? 0o644);\n}\n\nfunction applyEntries(\n cwd: string,\n entries: readonly CleanupEntry[],\n shouldDefer: () => boolean = () => false,\n): boolean {\n for (const entry of entries) {\n if (shouldDefer()) return false;\n const path = assertSafeClaudeCleanupTarget(cwd, entry.path);\n if (observedSha(path) !== entry.before_sha256) {\n throw new Error(`Claude cleanup target changed after planning: ${entry.path}`);\n }\n writeImage(cwd, path, entry.after_base64, entry.after_mode);\n }\n return true;\n}\n\nfunction writePluginModeMarker(cwd: string, transactionId: string): void {\n const marker = containedClaudeCleanupPath(cwd, CLAUDE_MIGRATION_SCHEMA.paths.pluginMarker);\n mkdirSync(nodePath.dirname(marker), { recursive: true });\n writeDurableFile(\n marker,\n `${JSON.stringify({ schema_version: 1, mode: 'plugin', transaction_id: transactionId })}\\n`,\n { mode: 0o600 },\n );\n}\n\nfunction unresolvedPaths(legacy: ClaudeLegacyObservation): string[] {\n return [\n ...legacy.conflictingFiles,\n ...legacy.conflictingHooks.map(\n hook => `.claude/settings.json#hooks.${hook.event}[${String(hook.index)}]`,\n ),\n ...(legacy.settingsError === undefined ? [] : ['.claude/settings.json']),\n ];\n}\n\nfunction automaticAdvisory(paths: readonly string[]): string | undefined {\n if (paths.length === 0) return undefined;\n return `Safeword removed the old Claude integration it could verify, but preserved unrecognized content at ${paths.join(', ')}. Review those paths; your prompt was not blocked.`;\n}\n\nfunction recordAutomaticAttention(\n cwd: string,\n options: AutomaticClaudeMigrationOptions,\n classification: string,\n advisory: string,\n): void {\n writeClaudeMigrationAttention(cwd, {\n schema_version: 1,\n state_digest: advisoryStateDigest(advisory),\n plugin_version: options.pluginVersion,\n catalogue_sha256: options.catalogueSha256,\n watched_settings_sha256: claudeWatchedSettingsDigest(cwd),\n classification,\n advisory,\n });\n}\n\nfunction waitForPluginMode(cwd: string, deadline: number, now: () => number): boolean {\n const marker = containedClaudeCleanupPath(cwd, CLAUDE_MIGRATION_SCHEMA.paths.pluginMarkerV2);\n const pause = new Int32Array(new SharedArrayBuffer(4));\n const maximumChecks = 25;\n for (let checks = 0; checks < maximumChecks && now() < deadline; checks += 1) {\n if (existsSync(marker)) return true;\n const remaining = Math.max(1, deadline - now());\n Atomics.wait(pause, 0, 0, Math.min(20, remaining));\n }\n return existsSync(marker);\n}\n\nfunction writeAutomaticPluginMode(cwd: string, transaction: CleanupTransaction): void {\n const pluginMode = transaction.plugin_mode;\n if (pluginMode === undefined) {\n writePluginModeMarker(cwd, transaction.transaction_id);\n return;\n }\n writeClaudePluginMode(\n cwd,\n createClaudePluginMode({\n plugin_version: pluginMode.plugin_version,\n hook_manifest_sha256: pluginMode.hook_manifest_sha256,\n catalogue_sha256: pluginMode.catalogue_sha256,\n unresolved_paths: pluginMode.unresolved_paths,\n advisory: pluginMode.advisory,\n transaction_id: transaction.transaction_id,\n }),\n );\n}\n\nfunction cleanupFailure(error: unknown, classification = 'coexistence'): CliResult {\n return createResult({\n state: 'failed',\n errors: [{ code: 'CLAUDE_CLEANUP_FAILED', message: String(error), retryable: true }],\n nextActions: [{ command: 'safeword claude recover', mutates: true, requiresHuman: true }],\n data: { command: 'claude cleanup', classification },\n });\n}\n\nexport function migrateClaudeLegacyAutomatically(\n cwd: string,\n options: AutomaticClaudeMigrationOptions,\n): AutomaticClaudeMigrationResult {\n const now = options.now ?? Date.now;\n let projectRoot: string | undefined;\n try {\n projectRoot = canonicalClaudeProjectRoot(cwd);\n return performAutomaticMigration(projectRoot, options, now);\n } catch (error) {\n const advisory = `Safeword preserved the old Claude integration after cleanup could not finish: ${error instanceof Error ? error.message : String(error)} Your prompt was not blocked; run \\`safeword claude recover\\` to repair it.`;\n if (projectRoot !== undefined) {\n try {\n recordAutomaticAttention(projectRoot, options, 'migration-error', advisory);\n } catch {\n // The prompt must remain successful even when durable attention cannot be recorded.\n }\n }\n return {\n state: 'attention',\n advisory,\n unresolvedPaths: [],\n };\n }\n}\n\nfunction recoveredAutomaticResult(projectRoot: string): AutomaticClaudeMigrationResult {\n const recovered = recoverClaudeCleanup(projectRoot);\n if (recovered.state !== 'failed') return { state: 'complete', unresolvedPaths: [] };\n const detail =\n recovered.errors?.[0]?.message ?? 'the recorded cleanup transaction could not be read safely';\n return {\n state: 'attention',\n advisory: `Safeword preserved the old Claude integration because automatic recovery could not finish: ${detail} Your prompt was not blocked; run \\`safeword claude recover\\` to repair it.`,\n unresolvedPaths: [],\n };\n}\n\nfunction writeObservedPluginMode(\n projectRoot: string,\n options: AutomaticClaudeMigrationOptions,\n unresolved: readonly string[],\n advisory: string | undefined,\n): AutomaticClaudeMigrationResult {\n writeClaudePluginMode(\n projectRoot,\n createClaudePluginMode({\n plugin_version: options.pluginVersion,\n hook_manifest_sha256: options.hookManifestSha256,\n catalogue_sha256: options.catalogueSha256,\n unresolved_paths: unresolved,\n advisory,\n }),\n );\n return { state: 'complete', advisory, unresolvedPaths: unresolved };\n}\n\nfunction claimAutomaticTransaction(\n projectRoot: string,\n transaction: CleanupTransaction,\n options: AutomaticClaudeMigrationOptions,\n now: () => number,\n unresolved: readonly string[],\n): AutomaticClaudeMigrationResult | undefined {\n try {\n writeTransaction(projectRoot, transaction);\n return undefined;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;\n if (waitForPluginMode(projectRoot, options.deadline, now)) {\n return { state: 'complete', unresolvedPaths: unresolved };\n }\n return {\n state: 'deferred',\n advisory:\n 'Another Safeword process is retiring the old Claude integration. Your prompt was not blocked; the next prompt will verify that it finished.',\n unresolvedPaths: unresolved,\n };\n }\n}\n\n/** Defers to whichever process already claimed the cleanup transaction. */\nfunction concurrentMigrationResult(\n projectRoot: string,\n options: AutomaticClaudeMigrationOptions,\n now: () => number,\n): AutomaticClaudeMigrationResult {\n const concurrentDeadline = Math.min(options.deadline, now() + 500);\n if (waitForPluginMode(projectRoot, concurrentDeadline, now)) {\n return { state: 'complete', unresolvedPaths: [] };\n }\n if (now() >= options.deadline) {\n return {\n state: 'deferred',\n advisory:\n 'Another Safeword process is retiring the old Claude integration. Your prompt was not blocked; the next prompt will verify that it finished.',\n unresolvedPaths: [],\n };\n }\n return recoveredAutomaticResult(projectRoot);\n}\n\n/**\n * Reads the before-images for a planned contraction.\n *\n * Planning happens before the exclusive transaction claim, so a process that\n * loses the race can be part-way through reading files the winner is already\n * deleting. That is an ordinary lost race, not a failure to report: returning\n * undefined routes it to the same deferral path as an already-claimed\n * transaction, instead of surfacing an ENOENT as a repair advisory.\n */\nfunction planCleanupEntries(\n projectRoot: string,\n mutations: readonly { path: string; content: string | null }[],\n): CleanupEntry[] | undefined {\n try {\n return mutations.map(mutation => entryFor(projectRoot, mutation));\n } catch (error) {\n if (existsSync(transactionPath(projectRoot))) return undefined;\n throw error;\n }\n}\n\nfunction performAutomaticMigration(\n projectRoot: string,\n options: AutomaticClaudeMigrationOptions,\n now: () => number,\n): AutomaticClaudeMigrationResult {\n if (now() >= options.deadline) {\n return {\n state: 'deferred',\n advisory: 'Safeword deferred old Claude integration cleanup until the next prompt.',\n unresolvedPaths: [],\n };\n }\n if (existsSync(transactionPath(projectRoot)))\n return concurrentMigrationResult(projectRoot, options, now);\n const legacy = observeClaudeLegacy(projectRoot);\n const unresolved = unresolvedPaths(legacy);\n const advisory = automaticAdvisory(unresolved);\n const mutations = claudeLegacyMutations(projectRoot);\n if (mutations.length === 0) {\n return writeObservedPluginMode(projectRoot, options, unresolved, advisory);\n }\n const entries = planCleanupEntries(projectRoot, mutations);\n if (entries === undefined) return concurrentMigrationResult(projectRoot, options, now);\n const transaction: CleanupTransaction = {\n schema_version: 1,\n transaction_id: randomUUID(),\n disposition: 'complete-forward',\n entries,\n plugin_mode: {\n plugin_version: options.pluginVersion,\n hook_manifest_sha256: options.hookManifestSha256,\n catalogue_sha256: options.catalogueSha256,\n unresolved_paths: unresolved,\n advisory,\n },\n };\n const contention = claimAutomaticTransaction(projectRoot, transaction, options, now, unresolved);\n if (contention !== undefined) return contention;\n if (!applyEntries(projectRoot, transaction.entries, () => now() >= options.deadline)) {\n return {\n state: 'deferred',\n advisory: 'Safeword will finish removing its old Claude integration on the next prompt.',\n unresolvedPaths: unresolved,\n };\n }\n writeAutomaticPluginMode(projectRoot, transaction);\n rmSync(transactionPath(projectRoot), { force: true });\n return { state: 'complete', advisory, unresolvedPaths: unresolved };\n}\n\nfunction parseTransaction(cwd: string): CleanupTransaction {\n const value = JSON.parse(readFileSync(transactionPath(cwd), 'utf8')) as CleanupTransaction;\n if (value.schema_version !== 1 || !Array.isArray(value.entries))\n throw new Error('Claude cleanup transaction is malformed.');\n return value;\n}\n\nfunction pendingRecoveryEntries(\n projectRoot: string,\n transaction: CleanupTransaction,\n): CleanupEntry[] {\n const forward = transaction.disposition === 'complete-forward';\n const pending: CleanupEntry[] = [];\n for (const entry of transaction.entries) {\n const path = assertSafeClaudeCleanupTarget(projectRoot, entry.path);\n const current = observedSha(path);\n const source = forward ? entry.before_sha256 : entry.after_sha256;\n const destination = forward ? entry.after_sha256 : entry.before_sha256;\n if (current === destination) continue;\n if (current !== source) throw new Error(`Claude recovery conflict at ${entry.path}`);\n pending.push(entry);\n }\n return pending;\n}\n\nfunction applyRecoveryEntries(\n projectRoot: string,\n transaction: CleanupTransaction,\n pending: readonly CleanupEntry[],\n): void {\n const forward = transaction.disposition === 'complete-forward';\n for (const entry of pending) {\n const path = containedClaudeCleanupPath(projectRoot, entry.path);\n writeImage(\n projectRoot,\n path,\n forward ? entry.after_base64 : entry.before_base64,\n forward ? entry.after_mode : entry.before_mode,\n );\n }\n}\n\nfunction completedRecoveryResult(projectRoot: string, transaction: CleanupTransaction): CliResult {\n if (transaction.disposition === 'complete-forward') {\n writeAutomaticPluginMode(projectRoot, transaction);\n }\n rmSync(transactionPath(projectRoot), { force: true });\n return createResult({\n state: 'changed',\n data: {\n command: 'claude recover',\n classification:\n transaction.disposition === 'complete-forward' ? 'plugin-mode' : 'cleanup-ready',\n },\n });\n}\n\nexport function recoverClaudeCleanup(cwd: string): CliResult {\n let projectRoot: string;\n try {\n projectRoot = canonicalClaudeProjectRoot(cwd);\n } catch (error) {\n return cleanupFailure(error, 'recovery-required');\n }\n if (!existsSync(transactionPath(projectRoot))) {\n return createResult({\n state: 'healthy',\n data: { command: 'claude recover', classification: 'plugin-mode' },\n });\n }\n try {\n const transaction = parseTransaction(projectRoot);\n applyRecoveryEntries(\n projectRoot,\n transaction,\n pendingRecoveryEntries(projectRoot, transaction),\n );\n return completedRecoveryResult(projectRoot, transaction);\n } catch (error) {\n return createResult({\n state: 'failed',\n errors: [{ code: 'CLAUDE_RECOVERY_CONFLICT', message: String(error), retryable: true }],\n nextActions: [\n { command: 'resolve the reported recovery conflict', mutates: false, requiresHuman: true },\n ],\n data: { command: 'claude recover', classification: 'recovery-required' },\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,SAAS,YAAY,kBAAkB;AACvC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,OAAO,cAAc;AAErB,SAAS,YAAY,QAAQ,OAAO,aAAa;AAsDjD,SAAS,OAAO,SAAkC;AAChD,SAAO,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAC1D;AAEA,SAAS,qBAAqB,SAA0B;AACtD,MAAI,QAAQ;AACZ,QAAM,SAAS,EAAE,WAAW,MAAO,QAAQ,KAAM,CAAC;AAClD,SAAO;AACT;AAEA,SAAS,iBACP,KACA,QACsD;AACtD,QAAM,WAAW;AACjB,QAAM,OAAO,SAAS,KAAK,KAAK,QAAQ;AACxC,MAAI,CAAC,WAAW,IAAI,KAAK,OAAO,gBAAgB,WAAW,EAAG,QAAO;AACrE,QAAM,WAAW,aAAa,MAAM,MAAM;AAC1C,QAAM,SAAS,MAAM,QAAQ;AAC7B,QAAM,QAAS,OAAO,SAAmD,CAAC;AAC1E,QAAM,yBAAyB,OAAO,OAAO,KAAK,EAAE,MAAM,aAAW,MAAM,QAAQ,OAAO,CAAC;AAC3F,QAAM,YAAY,OAAO,OAAO,KAAK,EAAE;AAAA,IACrC,CAAC,OAAO,YAAY,SAAS,MAAM,QAAQ,OAAO,IAAI,QAAQ,SAAS;AAAA,IACvE;AAAA,EACF;AACA,QAAM,wBACJ,OAAO,KAAK,MAAM,EAAE,WAAW,KAC/B,0BACA,cAAc,OAAO,gBAAgB,UACrC,CAAC,qBAAqB,QAAQ;AAChC,MAAI,sBAAuB,QAAO,EAAE,MAAM,UAAU,SAAS,KAAK;AAElE,MAAI,UAAU;AACd,QAAM,aAAa,OAAO,gBAAgB,SAAS,CAAC,MAAM,UAAU;AAClE,UAAM,aAAa,MAAM,MAAM,cAAc,KAAK,KAAK;AACvD,WAAO,eAAe,IAAI,MAAM,QAAQ,KAAK,QAAQ;AAAA,EACvD,CAAC;AACD,aAAW,aAAa,YAAY;AAClC,cAAU;AAAA,MACR;AAAA,MACA,OAAO,SAAS,CAAC,SAAS,UAAU,OAAO,UAAU,KAAK,GAAG,QAAW;AAAA,QACtE,mBAAmB,EAAE,cAAc,MAAM,SAAS,EAAE;AAAA,MACtD,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,EACF;AACF;AAEO,SAAS,sBAAsB,KAAyD;AAC7F,QAAM,SAAS,oBAAoB,GAAG;AACtC,QAAM,QAAoD,OAAO,gBAAgB,IAAI,WAAS;AAAA,IAC5F;AAAA,IACA,SAAS;AAAA,EACX,EAAE;AACF,QAAM,WAAW,iBAAiB,KAAK,MAAM;AAC7C,MAAI,aAAa,OAAW,OAAM,KAAK,QAAQ;AAC/C,SAAO;AACT;AAEO,SAAS,gCACd,KACA,WACQ;AACR,SAAO;AAAA,IACL,KAAK;AAAA,MACH,UAAU,IAAI,cAAY;AACxB,cAAM,SAAS,8BAA8B,KAAK,SAAS,IAAI;AAC/D,eAAO,CAAC,SAAS,MAAM,OAAO,aAAa,MAAM,CAAC,GAAG,SAAS,OAAO;AAAA,MACvE,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,KAAqB;AAC5C,SAAO,2BAA2B,KAAK,wBAAwB,MAAM,WAAW;AAClF;AAEA,SAAS,iBAAiB,KAAa,aAAuC;AAC5E,QAAM,OAAO,gBAAgB,GAAG;AAChC,YAAU,SAAS,QAAQ,IAAI,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAClE,4BAA0B,MAAM,GAAG,KAAK,UAAU,aAAa,QAAW,CAAC,CAAC;AAAA,GAAM;AAAA,IAChF,MAAM;AAAA,EACR,CAAC;AACH;AAEA,SAAS,SAAS,KAAa,UAAkE;AAC/F,QAAM,OAAO,8BAA8B,KAAK,SAAS,IAAI;AAC7D,QAAM,SAAS,aAAa,IAAI;AAChC,QAAM,QAAQ,SAAS,YAAY,OAAO,OAAO,OAAO,KAAK,SAAS,OAAO;AAC7E,SAAO;AAAA,IACL,MAAM,SAAS;AAAA,IACf,eAAe,OAAO,MAAM;AAAA,IAC5B,eAAe,OAAO,SAAS,QAAQ;AAAA,IACvC,aAAa,UAAU,IAAI,EAAE,OAAO;AAAA,IACpC,cAAc,UAAU,OAAO,OAAO,OAAO,KAAK;AAAA,IAClD,cAAc,UAAU,OAAO,OAAO,MAAM,SAAS,QAAQ;AAAA,IAC7D,YAAY,UAAU,OAAO,OAAO,UAAU,IAAI,EAAE,OAAO;AAAA,EAC7D;AACF;AAEA,SAAS,YAAY,MAA6B;AAChD,SAAO,WAAW,IAAI,IAAI,OAAO,aAAa,IAAI,CAAC,IAAI;AACzD;AASA,SAAS,oBAAoB,MAAc,MAAoB;AAC7D,QAAM,gBAAgB,SAAS,QAAQ,IAAI;AAC3C,MAAI,YAAY,SAAS,QAAQ,SAAS,QAAQ,IAAI,CAAC;AACvD,SAAO,UAAU,WAAW,GAAG,aAAa,GAAG,SAAS,GAAG,EAAE,GAAG;AAC9D,QAAI;AACF,UAAI,YAAY,SAAS,EAAE,SAAS,EAAG;AACvC,gBAAU,SAAS;AAAA,IACrB,QAAQ;AAGN;AAAA,IACF;AACA,gBAAY,SAAS,QAAQ,SAAS;AAAA,EACxC;AACF;AAEA,SAAS,WAAW,MAAc,MAAc,SAAwB,MAA2B;AACjG,MAAI,YAAY,MAAM;AACpB,WAAO,MAAM,EAAE,OAAO,KAAK,CAAC;AAC5B,wBAAoB,MAAM,IAAI;AAC9B;AAAA,EACF;AACA,YAAU,SAAS,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AACrD,mBAAiB,MAAM,OAAO,KAAK,SAAS,QAAQ,GAAG,EAAE,MAAM,QAAQ,IAAM,CAAC;AAC9E,YAAU,MAAM,QAAQ,GAAK;AAC/B;AAEA,SAAS,aACP,KACA,SACA,cAA6B,MAAM,OAC1B;AACT,aAAW,SAAS,SAAS;AAC3B,QAAI,YAAY,EAAG,QAAO;AAC1B,UAAM,OAAO,8BAA8B,KAAK,MAAM,IAAI;AAC1D,QAAI,YAAY,IAAI,MAAM,MAAM,eAAe;AAC7C,YAAM,IAAI,MAAM,iDAAiD,MAAM,IAAI,EAAE;AAAA,IAC/E;AACA,eAAW,KAAK,MAAM,MAAM,cAAc,MAAM,UAAU;AAAA,EAC5D;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,KAAa,eAA6B;AACvE,QAAM,SAAS,2BAA2B,KAAK,wBAAwB,MAAM,YAAY;AACzF,YAAU,SAAS,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AACvD;AAAA,IACE;AAAA,IACA,GAAG,KAAK,UAAU,EAAE,gBAAgB,GAAG,MAAM,UAAU,gBAAgB,cAAc,CAAC,CAAC;AAAA;AAAA,IACvF,EAAE,MAAM,IAAM;AAAA,EAChB;AACF;AAEA,SAAS,gBAAgB,QAA2C;AAClE,SAAO;AAAA,IACL,GAAG,OAAO;AAAA,IACV,GAAG,OAAO,iBAAiB;AAAA,MACzB,UAAQ,+BAA+B,KAAK,KAAK,IAAI,OAAO,KAAK,KAAK,CAAC;AAAA,IACzE;AAAA,IACA,GAAI,OAAO,kBAAkB,SAAY,CAAC,IAAI,CAAC,uBAAuB;AAAA,EACxE;AACF;AAEA,SAAS,kBAAkB,OAA8C;AACvE,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO,sGAAsG,MAAM,KAAK,IAAI,CAAC;AAC/H;AAEA,SAAS,yBACP,KACA,SACA,gBACA,UACM;AACN,gCAA8B,KAAK;AAAA,IACjC,gBAAgB;AAAA,IAChB,cAAc,oBAAoB,QAAQ;AAAA,IAC1C,gBAAgB,QAAQ;AAAA,IACxB,kBAAkB,QAAQ;AAAA,IAC1B,yBAAyB,4BAA4B,GAAG;AAAA,IACxD;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,SAAS,kBAAkB,KAAa,UAAkB,KAA4B;AACpF,QAAM,SAAS,2BAA2B,KAAK,wBAAwB,MAAM,cAAc;AAC3F,QAAM,QAAQ,IAAI,WAAW,IAAI,kBAAkB,CAAC,CAAC;AACrD,QAAM,gBAAgB;AACtB,WAAS,SAAS,GAAG,SAAS,iBAAiB,IAAI,IAAI,UAAU,UAAU,GAAG;AAC5E,QAAI,WAAW,MAAM,EAAG,QAAO;AAC/B,UAAM,YAAY,KAAK,IAAI,GAAG,WAAW,IAAI,CAAC;AAC9C,YAAQ,KAAK,OAAO,GAAG,GAAG,KAAK,IAAI,IAAI,SAAS,CAAC;AAAA,EACnD;AACA,SAAO,WAAW,MAAM;AAC1B;AAEA,SAAS,yBAAyB,KAAa,aAAuC;AACpF,QAAM,aAAa,YAAY;AAC/B,MAAI,eAAe,QAAW;AAC5B,0BAAsB,KAAK,YAAY,cAAc;AACrD;AAAA,EACF;AACA;AAAA,IACE;AAAA,IACA,uBAAuB;AAAA,MACrB,gBAAgB,WAAW;AAAA,MAC3B,sBAAsB,WAAW;AAAA,MACjC,kBAAkB,WAAW;AAAA,MAC7B,kBAAkB,WAAW;AAAA,MAC7B,UAAU,WAAW;AAAA,MACrB,gBAAgB,YAAY;AAAA,IAC9B,CAAC;AAAA,EACH;AACF;AAEA,SAAS,eAAe,OAAgB,iBAAiB,eAA0B;AACjF,SAAO,aAAa;AAAA,IAClB,OAAO;AAAA,IACP,QAAQ,CAAC,EAAE,MAAM,yBAAyB,SAAS,OAAO,KAAK,GAAG,WAAW,KAAK,CAAC;AAAA,IACnF,aAAa,CAAC,EAAE,SAAS,2BAA2B,SAAS,MAAM,eAAe,KAAK,CAAC;AAAA,IACxF,MAAM,EAAE,SAAS,kBAAkB,eAAe;AAAA,EACpD,CAAC;AACH;AAEO,SAAS,iCACd,KACA,SACgC;AAChC,QAAM,MAAM,QAAQ,OAAO,KAAK;AAChC,MAAI;AACJ,MAAI;AACF,kBAAc,2BAA2B,GAAG;AAC5C,WAAO,0BAA0B,aAAa,SAAS,GAAG;AAAA,EAC5D,SAAS,OAAO;AACd,UAAM,WAAW,iFAAiF,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AACxJ,QAAI,gBAAgB,QAAW;AAC7B,UAAI;AACF,iCAAyB,aAAa,SAAS,mBAAmB,QAAQ;AAAA,MAC5E,QAAQ;AAAA,MAER;AAAA,IACF;AACA,WAAO;AAAA,MACL,OAAO;AAAA,MACP;AAAA,MACA,iBAAiB,CAAC;AAAA,IACpB;AAAA,EACF;AACF;AAEA,SAAS,yBAAyB,aAAqD;AACrF,QAAM,YAAY,qBAAqB,WAAW;AAClD,MAAI,UAAU,UAAU,SAAU,QAAO,EAAE,OAAO,YAAY,iBAAiB,CAAC,EAAE;AAClF,QAAM,SACJ,UAAU,SAAS,CAAC,GAAG,WAAW;AACpC,SAAO;AAAA,IACL,OAAO;AAAA,IACP,UAAU,8FAA8F,MAAM;AAAA,IAC9G,iBAAiB,CAAC;AAAA,EACpB;AACF;AAEA,SAAS,wBACP,aACA,SACA,YACA,UACgC;AAChC;AAAA,IACE;AAAA,IACA,uBAAuB;AAAA,MACrB,gBAAgB,QAAQ;AAAA,MACxB,sBAAsB,QAAQ;AAAA,MAC9B,kBAAkB,QAAQ;AAAA,MAC1B,kBAAkB;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO,EAAE,OAAO,YAAY,UAAU,iBAAiB,WAAW;AACpE;AAEA,SAAS,0BACP,aACA,aACA,SACA,KACA,YAC4C;AAC5C,MAAI;AACF,qBAAiB,aAAa,WAAW;AACzC,WAAO;AAAA,EACT,SAAS,OAAO;AACd,QAAK,MAAgC,SAAS,SAAU,OAAM;AAC9D,QAAI,kBAAkB,aAAa,QAAQ,UAAU,GAAG,GAAG;AACzD,aAAO,EAAE,OAAO,YAAY,iBAAiB,WAAW;AAAA,IAC1D;AACA,WAAO;AAAA,MACL,OAAO;AAAA,MACP,UACE;AAAA,MACF,iBAAiB;AAAA,IACnB;AAAA,EACF;AACF;AAGA,SAAS,0BACP,aACA,SACA,KACgC;AAChC,QAAM,qBAAqB,KAAK,IAAI,QAAQ,UAAU,IAAI,IAAI,GAAG;AACjE,MAAI,kBAAkB,aAAa,oBAAoB,GAAG,GAAG;AAC3D,WAAO,EAAE,OAAO,YAAY,iBAAiB,CAAC,EAAE;AAAA,EAClD;AACA,MAAI,IAAI,KAAK,QAAQ,UAAU;AAC7B,WAAO;AAAA,MACL,OAAO;AAAA,MACP,UACE;AAAA,MACF,iBAAiB,CAAC;AAAA,IACpB;AAAA,EACF;AACA,SAAO,yBAAyB,WAAW;AAC7C;AAWA,SAAS,mBACP,aACA,WAC4B;AAC5B,MAAI;AACF,WAAO,UAAU,IAAI,cAAY,SAAS,aAAa,QAAQ,CAAC;AAAA,EAClE,SAAS,OAAO;AACd,QAAI,WAAW,gBAAgB,WAAW,CAAC,EAAG,QAAO;AACrD,UAAM;AAAA,EACR;AACF;AAEA,SAAS,0BACP,aACA,SACA,KACgC;AAChC,MAAI,IAAI,KAAK,QAAQ,UAAU;AAC7B,WAAO;AAAA,MACL,OAAO;AAAA,MACP,UAAU;AAAA,MACV,iBAAiB,CAAC;AAAA,IACpB;AAAA,EACF;AACA,MAAI,WAAW,gBAAgB,WAAW,CAAC;AACzC,WAAO,0BAA0B,aAAa,SAAS,GAAG;AAC5D,QAAM,SAAS,oBAAoB,WAAW;AAC9C,QAAM,aAAa,gBAAgB,MAAM;AACzC,QAAM,WAAW,kBAAkB,UAAU;AAC7C,QAAM,YAAY,sBAAsB,WAAW;AACnD,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,wBAAwB,aAAa,SAAS,YAAY,QAAQ;AAAA,EAC3E;AACA,QAAM,UAAU,mBAAmB,aAAa,SAAS;AACzD,MAAI,YAAY,OAAW,QAAO,0BAA0B,aAAa,SAAS,GAAG;AACrF,QAAM,cAAkC;AAAA,IACtC,gBAAgB;AAAA,IAChB,gBAAgB,WAAW;AAAA,IAC3B,aAAa;AAAA,IACb;AAAA,IACA,aAAa;AAAA,MACX,gBAAgB,QAAQ;AAAA,MACxB,sBAAsB,QAAQ;AAAA,MAC9B,kBAAkB,QAAQ;AAAA,MAC1B,kBAAkB;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACA,QAAM,aAAa,0BAA0B,aAAa,aAAa,SAAS,KAAK,UAAU;AAC/F,MAAI,eAAe,OAAW,QAAO;AACrC,MAAI,CAAC,aAAa,aAAa,YAAY,SAAS,MAAM,IAAI,KAAK,QAAQ,QAAQ,GAAG;AACpF,WAAO;AAAA,MACL,OAAO;AAAA,MACP,UAAU;AAAA,MACV,iBAAiB;AAAA,IACnB;AAAA,EACF;AACA,2BAAyB,aAAa,WAAW;AACjD,SAAO,gBAAgB,WAAW,GAAG,EAAE,OAAO,KAAK,CAAC;AACpD,SAAO,EAAE,OAAO,YAAY,UAAU,iBAAiB,WAAW;AACpE;AAEA,SAAS,iBAAiB,KAAiC;AACzD,QAAM,QAAQ,KAAK,MAAM,aAAa,gBAAgB,GAAG,GAAG,MAAM,CAAC;AACnE,MAAI,MAAM,mBAAmB,KAAK,CAAC,MAAM,QAAQ,MAAM,OAAO;AAC5D,UAAM,IAAI,MAAM,0CAA0C;AAC5D,SAAO;AACT;AAEA,SAAS,uBACP,aACA,aACgB;AAChB,QAAM,UAAU,YAAY,gBAAgB;AAC5C,QAAM,UAA0B,CAAC;AACjC,aAAW,SAAS,YAAY,SAAS;AACvC,UAAM,OAAO,8BAA8B,aAAa,MAAM,IAAI;AAClE,UAAM,UAAU,YAAY,IAAI;AAChC,UAAM,SAAS,UAAU,MAAM,gBAAgB,MAAM;AACrD,UAAM,cAAc,UAAU,MAAM,eAAe,MAAM;AACzD,QAAI,YAAY,YAAa;AAC7B,QAAI,YAAY,OAAQ,OAAM,IAAI,MAAM,+BAA+B,MAAM,IAAI,EAAE;AACnF,YAAQ,KAAK,KAAK;AAAA,EACpB;AACA,SAAO;AACT;AAEA,SAAS,qBACP,aACA,aACA,SACM;AACN,QAAM,UAAU,YAAY,gBAAgB;AAC5C,aAAW,SAAS,SAAS;AAC3B,UAAM,OAAO,2BAA2B,aAAa,MAAM,IAAI;AAC/D;AAAA,MACE;AAAA,MACA;AAAA,MACA,UAAU,MAAM,eAAe,MAAM;AAAA,MACrC,UAAU,MAAM,aAAa,MAAM;AAAA,IACrC;AAAA,EACF;AACF;AAEA,SAAS,wBAAwB,aAAqB,aAA4C;AAChG,MAAI,YAAY,gBAAgB,oBAAoB;AAClD,6BAAyB,aAAa,WAAW;AAAA,EACnD;AACA,SAAO,gBAAgB,WAAW,GAAG,EAAE,OAAO,KAAK,CAAC;AACpD,SAAO,aAAa;AAAA,IAClB,OAAO;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,gBACE,YAAY,gBAAgB,qBAAqB,gBAAgB;AAAA,IACrE;AAAA,EACF,CAAC;AACH;AAEO,SAAS,qBAAqB,KAAwB;AAC3D,MAAI;AACJ,MAAI;AACF,kBAAc,2BAA2B,GAAG;AAAA,EAC9C,SAAS,OAAO;AACd,WAAO,eAAe,OAAO,mBAAmB;AAAA,EAClD;AACA,MAAI,CAAC,WAAW,gBAAgB,WAAW,CAAC,GAAG;AAC7C,WAAO,aAAa;AAAA,MAClB,OAAO;AAAA,MACP,MAAM,EAAE,SAAS,kBAAkB,gBAAgB,cAAc;AAAA,IACnE,CAAC;AAAA,EACH;AACA,MAAI;AACF,UAAM,cAAc,iBAAiB,WAAW;AAChD;AAAA,MACE;AAAA,MACA;AAAA,MACA,uBAAuB,aAAa,WAAW;AAAA,IACjD;AACA,WAAO,wBAAwB,aAAa,WAAW;AAAA,EACzD,SAAS,OAAO;AACd,WAAO,aAAa;AAAA,MAClB,OAAO;AAAA,MACP,QAAQ,CAAC,EAAE,MAAM,4BAA4B,SAAS,OAAO,KAAK,GAAG,WAAW,KAAK,CAAC;AAAA,MACtF,aAAa;AAAA,QACX,EAAE,SAAS,0CAA0C,SAAS,OAAO,eAAe,KAAK;AAAA,MAC3F;AAAA,MACA,MAAM,EAAE,SAAS,kBAAkB,gBAAgB,oBAAoB;AAAA,IACzE,CAAC;AAAA,EACH;AACF;","names":[]}
|